Skip to content

Latest commit

 

History

History
86 lines (67 loc) · 3.95 KB

File metadata and controls

86 lines (67 loc) · 3.95 KB

Deploying to Cloud Run

The app deploys as one Cloud Run service that serves the SPA, the REST API, and the WebSocket connection (same-origin — no proxy/CORS in prod), wired to:

  • Cloud SQL (Postgres + pgvector) — durable data, via Cloud Run's native connector.
  • Memorystore (Redis) — pub/sub + per-session lock, via a Serverless VPC connector.
  • Cloud Storage — a bucket mounted for generated images.
  • Vertex AI (Gemini + Imagen) — via the service's own identity (ADC), no key files.

The GCP infrastructure is Terraform (infra/); the app is built and deployed by GitHub Actions (.github/workflows/deploy.yml) using Workload Identity Federation (no service-account keys).

Scaling. Live session state lives in Redis (shared) with a per-session lock, so the service is safe to scale out: the workflow runs --min-instances=1 (warm) and --max-instances=5 (scales under load). Postgres is the durable copy.

1. Provision infrastructure (Terraform)

Everything in GCP — Cloud SQL, Memorystore + VPC connector, the image bucket, Artifact Registry, both service accounts + IAM, and Workload Identity Federation — is declared in infra/. One-time:

cd infra
cp terraform.tfvars.example terraform.tfvars     # set project + github_repo
gcloud auth application-default login             # your account (Owner/Editor)
terraform init && terraform apply

See infra/README.md for details (billing + a default VPC are prerequisites).

2. Set GitHub secrets from the Terraform outputs

Repo → Settings → Secrets and variables → Actions. Output names == secret names:

cd infra
for k in GCP_PROJECT WIF_PROVIDER DEPLOY_SERVICE_ACCOUNT RUNTIME_SERVICE_ACCOUNT \
         CLOUDSQL_INSTANCE VPC_CONNECTOR IMAGE_BUCKET REDIS_URL; do
  gh secret set "$k" -b "$(terraform output -raw $k)"
done
gh secret set DATABASE_URL -b "$(terraform output -raw DATABASE_URL)"

(Or copy them in by hand from terraform output.)

Secret Source
GCP_PROJECT, WIF_PROVIDER, DEPLOY_SERVICE_ACCOUNT, RUNTIME_SERVICE_ACCOUNT terraform output
CLOUDSQL_INSTANCE, VPC_CONNECTOR, IMAGE_BUCKET terraform output
DATABASE_URL, REDIS_URL terraform output (DATABASE_URL is sensitive)

3. Deploy

git push origin main      # or: Actions tab → "Deploy to Cloud Run" → Run workflow

The workflow runs tests, builds the image, pushes it to Artifact Registry, deploys to Cloud Run, and prints the service URL.


Notes

  • pgvector is created by the app on startup (CREATE EXTENSION IF NOT EXISTS vector); Cloud SQL grants API-created users cloudsqlsuperuser, which can create it — no manual SQL step.
  • Region. Everything runs in europe-west2 (London) — infra, the Gemini DM, Imagen, and the semantic-recall embeddings (text-embedding-004, §6) are all served there; the embedder inherits GCP_LOCATION, so no extra env is needed (override with GEMINI_EMBED_MODEL if desired). The one exception is the image-consistency model gemini-2.5-flash-image, which isn't offered in europe-west2, so those reference-conditioned calls go to europe-west1 via GEMINI_EDIT_LOCATION (set in the workflow). Both are EU regions.
  • Scaling. Live session state is shared via Redis with a per-session lock, so instances can scale horizontally (WebSocket fan-out is pub/sub; each turn loads the current state under the lock). --max-instances is set to 5 — raise as needed.
  • Cost. Cloud SQL db-f1-micro + Memorystore Basic 1 GB + the VPC connector are the ongoing baseline; Vertex (Gemini/Imagen) is per-call. To drop Redis, remove infra/redis.tf and the VPC_CONNECTOR/REDIS_URL usage in the workflow.
  • Secrets hardening. DATABASE_URL/REDIS_URL are passed as env vars; for stricter setups move them to Secret Manager and use --set-secrets.