Skip to content

GCP Overview

One project, one region, one cluster, many namespaces. Tomoda's GCP footprint is intentionally small so that every operator can hold the whole topology in their head.

Single-project setup

There is no separate tomoda-dev and tomoda-prod project. Everything runs in development-485000 in us-central1 and is isolated by Kubernetes namespace. The project name is a historical artifact — treat it as the production project.

Topology at a glance

GCP · development-485000 · us-central1
GKE cluster · gke-tomoda
tomoda-api pods
tomoda-async pods
frontend pods
CNPG Postgres
Redis
Photon
Cloud Build
push
Artifact Registry
GCS buckets tfstate · backups · photon-index-usc1 · traces
GCP Secret Manager
AWS · us-east-2
CloudFront
S3 tomoda-assets-*
AWS Secrets Manager uploader creds
GKE is the focal point. Pods pull images from Artifact Registry (built by Cloud Build), read/write GCS via Workload Identity (CNPG backups, Photon index), and ESO syncs secrets in from both GCP SM and AWS SM. The AWS account exists only for the asset CDN plus the uploader credentials the backend needs to PutObject into S3.

What lives where

Concern Resource Page
Compute GKE cluster + 2 node pools GKE
Network Custom VPC + secondary ranges VPC
CI Cloud Build triggers + SA Cloud Build
Images 2 Artifact Registry repos Artifact Registry
GitOps Argo CD via Helm Argo CD
Auth IAP brand + OAuth client OAuth & Dex
Geocoder index …-photon-index-usc1 GCS bucket Photon Indexer
DB backups tomoda-db-backups-… GCS bucket Backup
Identity Workload Identity bindings IAM

Environment isolation

Because there is only one project, "dev" and "prod" are not GCP-level boundaries. They show up as:

  • Kubernetes namespacestomoda-dev, tomoda-prod, data (single namespace, holds both postgres-dev and postgres-prod clusters).
  • Artifact Registry repostomoda-dev-repo for main-branch builds, tomoda-prod-repo for semver-tag builds. Cloud Build pushes to whichever repo the trigger configures.
  • OAuth client IDs — three sets of Google OAuth client IDs (web/iOS/Android) baked into Cloud Build substitutions: one set for dev, one for prod, plus an internal one for middleware tools like Argo CD itself.

If you need stronger isolation later (separate billing, separate IAM blast radius, separate APIs), the migration path is to split the GKE cluster and node pools into a new project; the Terraform code is already parameterised on var.project_id.

Terraform workflow

cd infrastructure/gcp
terraform init                            # connects to gs://development-485000-tfstate
terraform plan  -var-file=terraform.tfvars
terraform apply -var-file=terraform.tfvars

The infrastructure/gcp/README.md mentions workspaces (internal / development / production), but the live environment runs the default workspace and the terraform.tfvars checked in points at development-485000. Do not create new workspaces without first migrating state — there is none for them.

Provider quirks

  • The Google provider sets user_project_override = true and billing_project = var.project_id. This stops API calls from being billed to Google's internal gcloud client project (764086051850) when operators are using user ADC, which would otherwise fail with SERVICE_DISABLED.
  • The kubernetes and helm providers authenticate against the GKE cluster using the operator's current gcloud access token — there is no kubeconfig file involved. terraform apply therefore requires container.clusters.getCredentials on gke-tomoda.