Skip to content

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.

Terminal window
git clone https://github.com/try-caret/arbium-terraform.git
cd arbium-terraform
git checkout chaindb-v<release-version>
cd gcp/customer
cp envs/example.tfvars envs/<environment>.tfvars

Authenticate both the CLI and Terraform application-default credentials:

Terminal window
gcloud auth login
gcloud auth application-default login
gcloud config set project <project-id>

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 = 1
general_node_max_size = 3
# Enable only when the project has regional GPU quota.
gpu_node_enabled = false
gpu_node_min_size = 0
gpu_node_max_size = 1
cloudsql_availability_type = "REGIONAL"
cloudsql_backup_retention_days = 7
cloudsql_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.

Terminal window
terraform init
terraform fmt -recursive
terraform validate
terraform plan -var-file=envs/<environment>.tfvars
terraform apply -var-file=envs/<environment>.tfvars

The apply creates the VPC, GKE cluster, private Cloud SQL instance, Secret Manager containers, workload identities, static ingress address, and optional Cloud Armor policy.

Terminal window
gcloud container clusters get-credentials \
"$(terraform output -raw cluster_name)" \
--region <region> \
--project <project-id>
kubectl get nodes

Install External Secrets Operator if it is not already present in the cluster:

Terminal window
helm repo add external-secrets https://charts.external-secrets.io
helm upgrade --install external-secrets external-secrets/external-secrets \
--namespace external-secrets --create-namespace --wait

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:

Terminal window
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=disable

The 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

Create an A record for the customer hostname using:

Terminal window
terraform output -raw ingress_static_ip_address

Google issues the managed certificate only after the hostname resolves to this address. Certificate provisioning begins after Helm creates the Ingress.

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: false

Enable 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.

Terminal window
terraform output cluster_name
terraform output cloudsql_connection_name
terraform output cloudsql_proxy_service_account_email
terraform output eso_service_account_email
terraform output ingress_static_ip_name
terraform output ingress_static_ip_address

Continue to 3. Configure & install Helm.