Google Cloud deployment
Owner: Cloud Ops
Returns to: 3. Configure & install Helm
This path provisions GKE, Cloud SQL for PostgreSQL, Google Secret Manager, Workload Identity, a static global address, and optional Cloud Armor.
1. Get the Terraform release
Section titled “1. Get the Terraform release”git clone https://github.com/try-caret/arbium-terraform.gitcd arbium-terraformgit checkout chaindb-v<release-version>cd gcp/customercp envs/example.tfvars envs/<environment>.tfvarsAuthenticate both the CLI and Terraform application-default credentials:
gcloud auth logingcloud auth application-default logingcloud config set project <project-id>2. Configure the GCP foundation
Section titled “2. Configure the GCP foundation”Set the project, region, network ranges, node sizing, and database protection. Keep the Kubernetes control-plane allowlist narrow in production.
project_id = "<gcp-project-id>"region = "us-east1"environment = "<environment>"name_prefix = "arbium"
general_node_machine_type = "e2-standard-2"general_node_min_size = 1general_node_max_size = 3
# Enable only when the project has regional GPU quota.gpu_node_enabled = falsegpu_node_min_size = 0gpu_node_max_size = 1
cloudsql_availability_type = "REGIONAL"cloudsql_backup_retention_days = 7cloudsql_deletion_protection = true
secret_names = [ "db", "scheduler", "scim", "sentry", "registry", "gemini", "enrollment", "jwt", "license", "admin-client-id", "admin-client-secret"]Ensure these APIs are enabled: Compute Engine, Kubernetes Engine, Cloud SQL, Service Networking, Secret Manager, and IAM Credentials. Terraform enables them, but enabling them once before the first apply avoids service-activation races.
3. Plan and apply
Section titled “3. Plan and apply”terraform initterraform fmt -recursiveterraform validateterraform plan -var-file=envs/<environment>.tfvarsterraform apply -var-file=envs/<environment>.tfvarsThe apply creates the VPC, GKE cluster, private Cloud SQL instance, Secret Manager containers, workload identities, static ingress address, and optional Cloud Armor policy.
4. Configure cluster access
Section titled “4. Configure cluster access”gcloud container clusters get-credentials \ "$(terraform output -raw cluster_name)" \ --region <region> \ --project <project-id>
kubectl get nodesInstall External Secrets Operator if it is not already present in the cluster:
helm repo add external-secrets https://charts.external-secrets.iohelm upgrade --install external-secrets external-secrets/external-secrets \ --namespace external-secrets --create-namespace --wait5. Populate Google Secret Manager
Section titled “5. Populate Google Secret Manager”Build the application database URL through the in-cluster Cloud SQL Auth Proxy.
Read the generated admin password from the secret identified by
cloudsql_admin_password_secret_id, URL-encode it once, then store the full URL
in arbium-<env>-db:
DB_SECRET_ID="$(terraform output -raw cloudsql_admin_password_secret_id)"DB_PASSWORD="$(gcloud secrets versions access latest \ --secret="$DB_SECRET_ID" --project=<gcp-project-id>)"DB_PASSWORD_ENCODED="$(printf '%s' "$DB_PASSWORD" | jq -sRr @uri)"
printf '%s' \ "postgres://chaindb_admin:${DB_PASSWORD_ENCODED}@arbium-cloud-sql-proxy.arbium.svc.cluster.local:5432/chaindb?sslmode=disable" \ | gcloud secrets versions add arbium-<env>-db \ --data-file=- --project=<gcp-project-id>The resulting secret value has this form:
postgres://chaindb_admin:<encoded-password>@arbium-cloud-sql-proxy.arbium.svc.cluster.local:5432/chaindb?sslmode=disableThe proxy authenticates to Cloud SQL with Workload Identity and encrypts its upstream connection. Application TLS is disabled only on the in-cluster pod-to-proxy hop.
Populate the remaining containers through the customer’s approved secret workflow:
| Secret | Value |
|---|---|
arbium-<env>-scheduler |
Random scheduler token |
arbium-<env>-enrollment |
Random enrollment secret |
arbium-<env>-jwt |
Random 32-byte JWT secret |
arbium-<env>-gemini |
Approved Gemini API key, when enabled |
arbium-<env>-license |
Arbium license key |
arbium-<env>-registry |
JSON {"username":"...","token":"..."} for GHCR |
arbium-<env>-scim |
Random SCIM bearer token, when SCIM is enabled |
arbium-<env>-admin-client-id |
Arbium Admin app client ID, when enabled |
arbium-<env>-admin-client-secret |
Arbium Admin app secret, when enabled |
6. Configure DNS
Section titled “6. Configure DNS”Create an A record for the customer hostname using:
terraform output -raw ingress_static_ip_addressGoogle issues the managed certificate only after the hostname resolves to this address. Certificate provisioning begins after Helm creates the Ingress.
7. Create the GCP provider values
Section titled “7. Create the GCP provider values”Save this as <environment>.gcp.values.local.yaml outside source control.
Omit the optional extraSecrets, scim, and admin blocks when the fleet
console is disabled.
global: region: <gcp-region>
imagePullSecrets: - name: ghcr-pull
externalSecrets: enabled: true provider: gcpsm projectID: <gcp-project-id> clusterLocation: <gcp-region> clusterName: <terraform-output-cluster_name> serviceAccount: annotations: iam.gke.io/gcp-service-account: <terraform-output-eso_service_account_email> dataMappings: DATABASE_URL: arbium-<env>-db SUPABASE_DB_URL: arbium-<env>-db CHAINDB_SCHEDULER_TOKEN: arbium-<env>-scheduler ARBOR_AGENT_ENROLLMENT_SECRET: arbium-<env>-enrollment ROOTS_INTUNE_PILOT_ENROLLMENT_SECRET: arbium-<env>-enrollment GEMINI_API_KEY: arbium-<env>-gemini JWT_SECRET: arbium-<env>-jwt ARBIUM_LICENSE_KEY: arbium-<env>-license imagePullSecret: enabled: true secretId: arbium-<env>-registry targetSecretName: ghcr-pull extraSecrets: scim-bearer: SCIM_BEARER_TOKEN: arbium-<env>-scim admin-ui-oidc: OIDC_CLIENT_ID: arbium-<env>-admin-client-id OIDC_CLIENT_SECRET: arbium-<env>-admin-client-secret
secrets: create: false existingSecret: chaindb-runtime
license: existingSecret: chaindb-runtime
cloudSqlProxy: enabled: true connectionName: <terraform-output-cloudsql_connection_name>
serviceAccount: cloudSqlProxy: annotations: iam.gke.io/gcp-service-account: <terraform-output-cloudsql_proxy_service_account_email>
config: databaseSsl: disable
ingress: enabled: true host: arbium.<customer-domain> annotations: kubernetes.io/ingress.global-static-ip-name: <terraform-output-ingress_static_ip_name> networking.gke.io/managed-certificates: chaindb-tls kubernetes.io/ingress.allow-http: "true"
tls: managedCertificate: enabled: true name: chaindb-tls domains: - arbium.<customer-domain>
embedder: enabled: true gpu: enabled: falseEnable GPU mode only after a GPU node advertises nvidia.com/gpu. If Cloud
Armor is enabled in Terraform, also enable backendConfig with the returned
policy name.
8. Record the provider outputs
Section titled “8. Record the provider outputs”terraform output cluster_nameterraform output cloudsql_connection_nameterraform output cloudsql_proxy_service_account_emailterraform output eso_service_account_emailterraform output ingress_static_ip_nameterraform output ingress_static_ip_addressContinue to 3. Configure & install Helm.