Skip to main content

Cloudreve on GKE Autopilot

Cloudreve on GKE Autopilot

Cloudreve is a popular open-source, self-hosted cloud storage and file-sharing platform written in Go. It provides a web UI for uploading, organising, previewing and sharing files, with pluggable storage back-ends. This module deploys Cloudreve on GKE Autopilot on top of the App_GKE foundation, which provisions and manages the shared Google Cloud and Kubernetes infrastructure.

This guide focuses on the cloud services Cloudreve uses and how to explore and operate them from the Google Cloud Console and the command line. For the mechanics that are common to every GKE application — Workload Identity, ingress, autoscaling, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC Service Controls, backups, and the deployment lifecycle — refer to the App_GKE foundation guide rather than repeating them here.


1. Overview

Cloudreve runs as a single Go binary serving both the web UI and file storage API. The deployment wires together a focused set of Google Cloud services:

CapabilityGoogle Cloud serviceNotes
ComputeGKE AutopilotSingle Go binary on port 5212, StatefulSet by default
PersistenceBlock Persistent Volume (via stateful_pvc_enabled)Mounted at /cloudreve; holds the embedded SQLite DB, conf.ini, and uploaded files
Object storageCloud StorageA storage bucket provisioned automatically, but only wired in as a GCS FUSE mount when the block PVC is disabled
DatabaseNoneCloudreve uses an embedded SQLite database on the block volume — no Cloud SQL instance is created
SecretsSecret ManagerNone created — the first-run admin password is generated by Cloudreve itself and printed to container logs
IngressKubernetes Gateway / Cloud Load BalancingCustom domain enabled by default; static IP reserved by default

Sensible defaults worth knowing up front:

  • No SQL database. database_type is fixed to NONE by Cloudreve_Common; every Cloud SQL-related variable is forwarded to the foundation only for interface compatibility and has no effect.
  • stateful_pvc_enabled = true by default — required, not optional. Cloudreve's embedded SQLite database and local file storage live together in its working directory, /cloudreve. A GCS FUSE mount there would corrupt SQLite's file locking, so the module defaults to a block PVC (StatefulSet) instead; workload_type need not be set separately.
  • Binary/data co-location is handled in the image build. Upstream's cloudreve/cloudreve image keeps both the cloudreve binary and its data in /cloudreve. This module's Dockerfile relocates the binary to /usr/local/bin/cloudreve in a multi-stage build (ENTRYPOINT ["/usr/local/bin/cloudreve"], WORKDIR /cloudreve), so mounting the PVC at /cloudreve only shadows data files, never the binary. See Section 3.
  • GCS volume and block PVC are mutually exclusive at the same path. The variant only mounts the auto-created storage bucket at /cloudreve (enable_gcs_storage_volume = !stateful_pvc_enabled) when the block PVC is off, avoiding a double-mount conflict — with the default stateful config, that bucket exists but is not mounted into the pod.
  • No Cloud SQL, no Redis. enable_cloudsql_volume defaults false and enable_redis is explicitly overridden to false in main.tf.
  • No injectable admin secret. Cloudreve generates its own initial admin password on first boot and prints it to container logs — no Secret Manager secret is created; secret_ids/secret_values are empty maps.
  • Single replica by default. min_instance_count = max_instance_count = 1, matching Cloudreve's lack of distributed/multi-node clustering support.
  • enable_pod_disruption_budget defaults true (unusual among app modules), pdb_min_available = "1", protecting the single stateful pod.
  • Custom domain and static IP are on by default (enable_custom_domain = true, reserve_static_ip = true), unlike many other application modules where these default off.

2. Google Cloud Services & How to Explore Them

All commands assume you have run gcloud container clusters get-credentials <cluster> --region $REGION --project $PROJECT and that PROJECT, REGION, and NAMESPACE are set. The namespace and other identifiers are reported in the deployment Outputs.

A. GKE Autopilot — the Cloudreve workload

Cloudreve pods are scheduled on Autopilot, which bills for the CPU/memory the pod actually requests. Because stateful_pvc_enabled = true by default, the workload is a StatefulSet with a single stable pod identity and a per-pod block PVC, not a Deployment.

  • Console: Kubernetes Engine → Workloads → filter for the Cloudreve workload for pods, revisions, and events. Kubernetes Engine → Services & Ingress shows the external IP / Gateway route.
  • CLI:
    kubectl get statefulsets,pods,svc -n "$NAMESPACE"
    kubectl logs -n "$NAMESPACE" statefulset/<service-name> --tail=100
    kubectl describe pod -n "$NAMESPACE" -l app=<service-name>

See App_GKE for how Autopilot, scaling, and the Deployment-vs-StatefulSet workload type decision are managed.

B. Block Persistent Volume (StatefulSet PVC)

Cloudreve's embedded SQLite database (cloudreve.db), generated conf.ini, and uploaded files all live under /cloudreve, the container's working directory. stateful_pvc_enabled = true provisions a per-pod block PVC (stateful_pvc_storage_class = standard-rwo by default, an SSD-backed Balanced PD) mounted at that path — a GCS FUSE mount here would break SQLite's file-locking semantics, so the block device is mandatory.

  • Console: Kubernetes Engine → Storage → filter for the Cloudreve PVC; Compute Engine → Disks shows the underlying Persistent Disk.
  • CLI:
    kubectl get pvc -n "$NAMESPACE"
    kubectl describe pvc -n "$NAMESPACE" -l app=<service-name>
    gcloud compute disks list --project "$PROJECT" --filter="name~cloudreve"

Remember that scaling to zero (kubectl scale --replicas=0) frees CPU/memory but keeps the PVC — only deleting the PVC (or the namespace) releases the SSD quota it draws. See App_GKE for the StatefulSet / PVC group mechanics and the SSD-vs-HDD storage-class trade-off.

C. Cloud Storage

A storage Cloud Storage bucket is created automatically by Cloudreve_Common, but it is only mounted into the pod as a GCS FUSE volume when stateful_pvc_enabled = false (avoiding a double-mount at /cloudreve with the block PVC). With the default stateful configuration, the bucket exists but sits unused unless you add it as an explicit gcs_volumes entry at a different mount path.

  • Console: Cloud Storage → Buckets → filter for the deployment's storage suffix.
  • CLI:
    gcloud storage buckets list --project "$PROJECT" --filter="name~storage"
    kubectl get pvc,pv -n "$NAMESPACE"

See App_GKE for CMEK options and the GCS Fuse CSI driver.

D. Secret Manager

Cloudreve_Common creates no Secret Manager secrets for Cloudreve itself — the first-run admin password is generated internally by Cloudreve and printed to container logs on first boot, not stored in Secret Manager. Any secrets you configure via secret_environment_variables are still projected through the standard Secret Store CSI mechanism.

  • Console: Security → Secret Manager.
  • CLI:
    gcloud secrets list --project "$PROJECT" --filter="name~cloudreve"
    kubectl logs -n "$NAMESPACE" statefulset/<service-name> --tail=200 | grep -i "admin\|password"

See App_GKE for the Secret Store CSI integration and rotation mechanics (rotation has no effect here since no service secret exists).

E. Networking & ingress

By default the workload uses enable_custom_domain = true with reserve_static_ip = true (Kubernetes Gateway API with a Google-managed certificate). service_type defaults to ClusterIP — the Gateway, not the Service, is the external entry point unless you switch to LoadBalancer.

  • Console: Network services → Load balancing / Gateways; VPC network → IP addresses.
  • CLI:
    kubectl get svc,gateway,httproute -n "$NAMESPACE"
    gcloud compute addresses list --project "$PROJECT"

See App_GKE for custom domains, Cloud CDN, and static IP details.

F. Cloud Logging & Monitoring

Pod stdout/stderr flow to Cloud Logging; GKE metrics flow to Cloud Monitoring. Optional uptime checks and alert policies are available (uptime_check_config.enabled defaults false).

  • Console: Logging → Logs Explorer; Monitoring → Dashboards / Alerting.
  • CLI:
    gcloud logging read 'resource.type="k8s_container" AND resource.labels.namespace_name="'"$NAMESPACE"'"' \
    --project "$PROJECT" --limit 50

3. Cloudreve Application Behaviour

  • No database initialisation job. Cloudreve_Common does not inject a default db-init/db-create job — Cloudreve has no SQL database to provision. initialization_jobs only runs jobs you explicitly supply.
  • First-boot self-setup, admin password in logs. On first start Cloudreve creates its SQLite schema on the mounted volume and generates the initial admin account, printing the generated password to container logs. There is no separate migration step and no Secret Manager secret to retrieve it from — capture it with kubectl logs before the log buffer rotates, then change it via the web UI.
  • Volume-shadowing is pre-fixed in the Dockerfile. Without the relocation described in Section 1, the block PVC mount at /cloudreve would shadow the co-located binary, producing exec ./cloudreve: no such file or directory (CrashLoopBackOff). This is a custom-build module (container_image_source = "custom", image_source = "custom" in Cloudreve_Common) precisely so this fix (modules/Cloudreve_Common/scripts/Dockerfile) can be baked in — it is not a bare pass-through of the upstream image. Editing the Dockerfile requires a rebuild (tofu taint 'module.app_gke.module.app_build.null_resource.build_and_push_application_image[0]' if a content-hash trigger misses the change).
  • Version pinning uses an app-specific build ARG. The Dockerfile reads CLOUDREVE_VERSION (pinned to 3.8.3 when application_version = "latest"), not the generic APP_VERSION the Foundation injects and would otherwise force to the unresolvable tag latest.
  • Health probe paths. Startup probe is HTTP GET / (initial_delay_seconds = 15, failure_threshold = 10, i.e. up to ~100s to become ready); liveness probe is HTTP GET / as well (initial_delay_seconds = 30, period_seconds = 30). Cloudreve has no dedicated health endpoint distinct from its web UI — / returns 200 once the server is serving.
  • Single-replica, OrderedReady semantics. With stateful_pod_management_policy left at its nullOrderedReady default and max_instance_count = 1, only one pod exists at a time; do not raise max_instance_count without verifying Cloudreve's own multi-node/clustering support (not managed by this module).
  • Inspect the running config and StatefulSet rollout:
    kubectl get statefulsets -n "$NAMESPACE"
    kubectl rollout status statefulset/<service-name> -n "$NAMESPACE"
    kubectl exec -n "$NAMESPACE" statefulset/<service-name> -- ls -la /cloudreve

4. Configuration Variables

Variables are grouped exactly as they appear on the deployment platform. Only settings specific to or notable for Cloudreve are listed; every other input is inherited from App_GKE with its standard behaviour and defaults.

Group 3 — Application Identity

VariableDefaultDescription
application_namecloudreveBase name for resources. Do not change after first deploy.
application_versionlatestcloudreve/cloudreve image tag; latest is pinned to 3.8.3 at build time via the CLOUDREVE_VERSION build ARG.
descriptionCloudreve — self-hosted cloud storage / file-sharing systemPopulates the GKE workload description.

Group 4 — Runtime & Scaling

VariableDefaultDescription
cpu_limit1000mCPU allocated to the Cloudreve container.
memory_limit1GiMemory allocated; size for file-serving and concurrent transfers.
min_instance_count / max_instance_count1 / 1Cloudreve has no distributed/clustering mode — keep both at 1.
container_port5212Fixed by Cloudreve_Common; the variable is not forwarded to App_GKE and has no effect.
enable_cloudsql_volumefalseCloudreve has no Cloud SQL database.
enable_image_mirroringtrueMirrors the built image into Artifact Registry.

Group 6 — GKE Backend & Cluster

VariableDefaultDescription
service_typeClusterIPExternal access goes through the Gateway (enable_custom_domain), not the Service, by default.
workload_typenullStatefulSetResolves automatically because stateful_pvc_enabled = true.
session_affinityNoneNo sticky routing configured by default.

Group 7 — StatefulSet Configuration

VariableDefaultDescription
stateful_pvc_enabledtrueRequired for Cloudreve — its SQLite DB and uploads must live on a block volume, not gcsfuse.
stateful_pvc_size20GiSize for the SQLite DB plus uploaded files; raise for larger libraries.
stateful_pvc_mount_path/cloudreveCloudreve's working directory — do not change without also updating the app's data-path expectations.
stateful_pvc_storage_classstandard-rwoSSD-backed Balanced PD; switch to standard (HDD) if the tight SSD_TOTAL_GB quota is a constraint (see App_GKE).
stateful_fs_group3000Matches the Cloudreve Helm chart's fsGroup convention (container runs as UID 1000/GID 2000) so the PVC is group-writable.

Group 9 — Reliability

VariableDefaultDescription
enable_pod_disruption_budgettrueOn by default (unusual among app modules) to protect the single stateful pod.
pdb_min_available"1"Requires the one pod to stay available during voluntary disruptions.

Group 10 — Observability & Health

VariableDefaultDescription
startup_probeHTTP GET /, initial_delay=15s, failure_threshold=10No dedicated health endpoint — Cloudreve serves / once ready.
liveness_probeHTTP GET /, initial_delay=30s, period=30sSame endpoint as the startup probe.

Group 14 — Cloud Storage

VariableDefaultDescription
gcs_volumes[]The auto-created storage bucket is only mounted at /cloudreve when stateful_pvc_enabled = false; otherwise it exists unused unless mounted at a different path here.

Group 15 — Redis

VariableDefaultDescription
enable_redistrue (App_GKE default) but overridden to false in main.tfCloudreve does not use Redis; the variable has no effect regardless of its setting.

Group 16 — Database Configuration

VariableDefaultDescription
database_typeNONEFixed by Cloudreve_Common — Cloudreve has no SQL database; all other database_*/db_*/sql_* variables are forwarded for foundation interface compatibility only and have no effect.

Group 19 — Custom Domain, Static IP & Networking

VariableDefaultDescription
enable_custom_domaintrueOn by default, unlike many other application modules.
reserve_static_iptrueStable external address across redeploys.
network_tags["nfsserver"]Default carries the nfsserver tag even though enable_nfs defaults false for Cloudreve — harmless unless NFS is separately enabled.

All other inputs follow standard App_GKE behaviour.


5. Outputs

These values are returned on a successful deployment and are the quickest way to locate and explore the running resources.

OutputDescription
service_nameKubernetes Service name.
namespaceNamespace the workload runs in.
service_cluster_ipIn-cluster ClusterIP.
stage_service_cluster_ipsMap of ClusterIPs for stage-specific services.
service_external_ipExternal LoadBalancer IP (when a static IP is reserved).
service_urlURL to reach Cloudreve.
storage_bucketsCreated Cloud Storage buckets (the storage bucket, mounted only if stateful_pvc_enabled = false).
network_name / network_exists / regionsVPC network, presence, available regions.
container_image / container_registryDeployed image and Artifact Registry repo.
monitoring_enabled / monitoring_notification_channelsMonitoring status and channels.
deployment_id / tenant_id / resource_prefixNaming identifiers.
project_id / project_numberProject identifiers.
initialization_jobsNames of any user-supplied initialization jobs (Cloudreve injects none by default).
statefulset_nameName of the StatefulSet.
cicd_enabled / cicd_configurationCI/CD status and details (repo, trigger, registry).
github_repository_url / github_repository_owner / github_repository_nameCI/CD GitHub details.
artifact_registry_repository / cloudbuild_trigger_name / cloudbuild_trigger_idRegistry and build trigger.
kubernetes_readyWhether the cluster/workload is ready.
vpc_sc_enabled / vpc_sc_perimeter_name / vpc_sc_dry_run_modeVPC-SC status.
audit_logging_enabled / artifact_registry_cmek_enabledAudit logging and CMEK status.

6. Configuration Pitfalls & Sensible Defaults

Risk: Critical (data loss / outage / security) — High (service degraded) — Medium (cost or partial degradation) — Low (minor).

Inherited plan-time validation. This module passes its configuration through the App_GKE foundation engine, which validates values and combinations at plan time — a StatefulSet forced alongside a stateless setting, IAP with no authorized identities, quota_memory_* given as bare integers, an out-of-range container_port/backup_retention_days. Invalid configuration fails the plan with a clear, named error before any resource is created, so most mistakes below are caught up front rather than at apply or runtime.

SettingSensible valueRiskConsequence if wrong
stateful_pvc_enabledtrueCriticalDisabling it without providing an equivalent block-storage mount lets SQLite live on gcsfuse (or ephemeral disk), risking database corruption or total data loss on pod recreation.
stateful_pvc_mount_path/cloudreveCriticalChanging this away from Cloudreve's working directory disconnects the persistent volume from where the app actually reads/writes its DB and uploads.
Dockerfile binary relocation (/usr/local/bin/cloudreve)Keep as shippedCriticalReverting to ENTRYPOINT ["./cloudreve"] inside /cloudreve re-introduces volume-shadowing: the block PVC mount hides the binary and the pod CrashLoopBackOffs with exec ./cloudreve: no such file or directory.
max_instance_count1HighCloudreve has no verified multi-node/clustering mode in this module; scaling beyond 1 risks concurrent writers against the same SQLite file (only one pod actually owns the PVC in OrderedReady StatefulSet mode, but do not assume higher counts are safe).
stateful_pvc_storage_classstandard-rwo (SSD); standard (HDD) under quota pressureMediumSSD draws the tight SSD_TOTAL_GB quota. Scaling to zero does not release the PVC — only deletion does.
Admin password retrievalCapture from kubectl logs immediately after first bootMediumThe generated admin password is only printed to container logs once; missing it locks you out of the first-run super-admin account until reset via the container.
quota_memory_requests / _limitsbinary units (4Gi, 8192Mi)CriticalBare integers are treated as bytes and block all pod scheduling in the namespace.
reserve_static_iptrueMediumWithout it, the external IP/Gateway address can change across redeploys, breaking DNS and bookmarked links.
gcs_volumes at /cloudreve while stateful_pvc_enabled = trueAvoidHighA GCS FUSE mount and the block PVC both targeting /cloudreve conflict; the Common module only enables the GCS mount when the block PVC is off.
backup_retention_days7 (raise for prod)MediumToo short for compliance retention.

For the foundation behaviour referenced throughout — IAM and Workload Identity, autoscaling, ingress and certificates, CI/CD, Cloud Armor, IAP, Binary Authorization, VPC-SC, backups, and image mirroring — see App_GKE. Cloudreve-specific application configuration shared with the Cloud Run variant is described in the Cloudreve_Common module (modules/Cloudreve_Common); a dedicated Cloudreve_Common.md guide does not yet exist in this documentation set.