Infrastructure and Deployment Guide (Google Cloud Platform)
This document details the technical procedures for deploying the Health Without Borders API to Google Cloud Platform (GCP). It covers resource provisioning, container building, secure secret management, service deployment, and CI/CD automation.
Architecture Overview
The system utilizes a fully serverless, highly available, and containerized architecture:
- Compute: Google Cloud Run (Stateless containers).
- Database: Google Cloud SQL (Managed PostgreSQL 15).
- Interoperability: Cloud Healthcare API (FHIR R4 Store for RDA bundles).
- Security: Secret Manager (Secure vault for passwords and keys).
- Registry: Artifact Registry (Docker image storage).
- CI/CD: Cloud Build (Serverless build pipeline).
⚙️ Environment Variables Reference
Throughout this guide, replace the following placeholders <...> with your specific project details:
<GCP_PROJECT_ID>: Your Google Cloud Project ID (e.g.,migrants-unicef).<PROJECT_NUMBER>: Your numeric GCP Project ID (used for service accounts).<REGION>: The GCP region for your resources (e.g.,us-central1).<DB_INSTANCE_NAME>: The name of your Cloud SQL server (e.g.,hwb-db-cluster).<DB_NAME>: The logical database inside the instance (e.g.,hwb_db).<DB_PASSWORD>: The password for thepostgresuser.<SECRET_KEY>: Your secure JWT signing key.<REPO_NAME>: Your Artifact Registry name (e.g.,hwb-repo).<CLOUD_RUN_SERVICE>: The name of your backend service (e.g.,hwb-backend-dev).
1. Prerequisites
Before proceeding, ensure the following requirements are met:
- GCP Project: An active Google Cloud project.
- Google Cloud SDK:
gcloudCLI installed and authenticated (gcloud auth login). - Python Environment: Python 3.11+ and the
uvpackage manager installed locally. - Permissions: The active user must have
EditororOwnerroles.
Set your default project in the CLI:
2. Service Enablement
Enable the required APIs to allow communication between GCP services.
gcloud services enable \
run.googleapis.com \
sqladmin.googleapis.com \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com \
healthcare.googleapis.com \
secretmanager.googleapis.com
3. Database Provisioning (Cloud SQL)
Cloud Run requires an external persistence layer for relational data. Since we enforce a strict "No Public IP" policy, we must first establish a VPC Peering connection between our network and Google's internal services.
1. Establish VPC Peering (Run Once per Project):
# Reserve private IP range for Google Services
gcloud compute addresses create google-managed-services-default \
--global \
--purpose=VPC_PEERING \
--prefix-length=16 \
--description="peering range for Google" \
--network=default
# Connect the peering
gcloud services vpc-peerings connect \
--service=servicenetworking.googleapis.com \
--ranges=google-managed-services-default \
--network=default \
--project=<GCP_PROJECT_ID>
2. Create the Cloud SQL Instance (Server):
Choose the appropriate command based on your target environment.
Option A: Development / Sandbox (Cost-Optimized)
gcloud sql instances create <DB_INSTANCE_NAME> \
--database-version=POSTGRES_15 \
--tier=db-f1-micro \
--region=<REGION> \
--storage-size=10GB \
--storage-type=SSD \
--no-storage-auto-increase \
--network=default \
--no-assign-ip \
--root-password="<DB_PASSWORD>"
Option B: Production (High Availability & Performance)
gcloud sql instances create <DB_INSTANCE_NAME> \
--database-version=POSTGRES_15 \
--tier=db-custom-2-8192 \
--region=<REGION> \
--availability-type=REGIONAL \
--storage-size=100GB \
--storage-type=SSD \
--storage-auto-increase \
--enable-point-in-time-recovery \
--network=default \
--no-assign-ip \
--root-password="<DB_PASSWORD>"
(Note: Production uses a dedicated 2-core 8GB RAM machine, is replicated across two zones for High Availability, and enables Point-in-Time recovery).
3. Create the Logical Database:
4. Security & Secret Manager Setup 🔒
To avoid hardcoded credentials in environment variables, store sensitive data in Secret Manager.
1. Create the secrets:
printf "<DB_PASSWORD>" | gcloud secrets create hwb-db-pass --data-file=-
printf "<SECRET_KEY>" | gcloud secrets create hwb-secret-key --data-file=-
2. Grant read access to Cloud Run's default service account:
(Replace <PROJECT_NUMBER> with your actual numeric project ID)
export COMPUTE_SA="<PROJECT_NUMBER>-compute@developer.gserviceaccount.com"
gcloud secrets add-iam-policy-binding hwb-db-pass \
--member="serviceAccount:${COMPUTE_SA}" \
--role="roles/secretmanager.secretAccessor"
gcloud secrets add-iam-policy-binding hwb-secret-key \
--member="serviceAccount:${COMPUTE_SA}" \
--role="roles/secretmanager.secretAccessor"
5. Healthcare & Artifact Registry Setup
1. Healthcare Interoperability (FHIR R4 Store):
gcloud healthcare datasets create <DATASET_NAME> --location=<REGION>
gcloud healthcare fhir-stores create <FHIR_STORE_NAME> \
--dataset=<DATASET_NAME> \
--location=<REGION> \
--version=R4 \
--enable-referential-integrity \
--enable-resource-versioning
2. Artifact Registry (Docker storage):
gcloud artifacts repositories create <REPO_NAME> \
--repository-format=docker \
--location=<REGION> \
--description="HWB Docker Repository"
6. Initial Manual Deployment (Bootstrap)
For the very first deployment, build and deploy manually to establish the Cloud Run service, its VPC connectors, and Secret Manager links.
1. Build the image:
gcloud builds submit \
--tag <REGION>-docker.pkg.dev/<GCP_PROJECT_ID>/<REPO_NAME>/backend:bootstrap \
.
2. Deploy to Cloud Run:
(Notice the use of --update-secrets instead of plain text environment variables for sensitive data).
gcloud run deploy <CLOUD_RUN_SERVICE> \
--image <REGION>-docker.pkg.dev/<GCP_PROJECT_ID>/<REPO_NAME>/backend:bootstrap \
--region <REGION> \
--allow-unauthenticated \
--add-cloudsql-instances="<GCP_PROJECT_ID>:<REGION>:<DB_INSTANCE_NAME>" \
--set-env-vars="INSTANCE_CONNECTION_NAME=<GCP_PROJECT_ID>:<REGION>:<DB_INSTANCE_NAME>" \
--set-env-vars="DB_USER=postgres" \
--set-env-vars="DB_NAME=<DB_NAME>" \
--set-env-vars="GCP_PROJECT_ID=<GCP_PROJECT_ID>" \
--set-env-vars="GCP_LOCATION=<REGION>" \
--set-env-vars="GCP_DATASET_ID=<DATASET_NAME>" \
--set-env-vars="GCP_FHIR_STORE_ID=<FHIR_STORE_NAME>" \
--update-secrets="DB_PASS=hwb-db-pass:latest,SECRET_KEY=hwb-secret-key:latest"
7. CI/CD Automation (Cloud Build) 🚀
For this project, Cloud Build is the primary CI/CD gate. This avoids dependency on GitHub-hosted runner billing and keeps validation/deploy inside GCP.
Trigger A: Pull Request quality gates
Create a trigger for pull requests targeting develop:
- Event: Pull request
- Base branch:
^develop$ - Configuration file:
/cloudbuild.pr.yaml - Behavior: Run lint, scoped type-check, and tests with coverage. No deploy step.
Trigger B: Deploy from develop
Create a trigger for merges/pushes to develop:
- Event: Push to branch
- Branch regex:
^develop$ - Configuration file:
/cloudbuild.yaml - Behavior: Run tests, build image, push image, deploy to Cloud Run.
Service account for triggers
Use a dedicated least-privilege service account where possible. At minimum it needs permissions for:
- Cloud Run deploy
- Artifact Registry push
- Secret Manager access (for deploy-time secret bindings)
- Cloud Build execution
If using the default Compute service account, ensure IAM is explicitly scoped and reviewed periodically.
8. Data Initialization (Schema & Seeding)
Because our database lacks a public IP for security reasons, initializing the database from a local laptop requires a temporary security bypass. We will temporarily assign a public IP, run our scripts securely through the encrypted Auth Proxy, and then lock the instance down again.
1. Temporarily Open the Vault (Assign Public IP):
(Wait 1-2 minutes for the instance to update).
2. Start the Cloud SQL Auth Proxy: In a new terminal window, open the secure encrypted tunnel:
3. Execute Initialization Scripts:
In a separate terminal window, force the DATABASE_URL to route through the local tunnel:
export DATABASE_URL="postgresql://postgres:<DB_PASSWORD>@127.0.0.1:5433/<DB_NAME>"
uv run python scripts/create_tables.py
uv run python scripts/create_generic_user.py
uv run python scripts/load_catalogs.py
4. Close the Vault (Revoke Public IP): Once the scripts complete successfully, immediately restore the maximum security posture:
9. Monitoring and Maintenance
- Application Logs: Cloud Run Console -> "Logs" tab.
- Database Performance: Cloud SQL Console.
- FHIR Store Metrics: Cloud Healthcare API Dashboard.
- CI/CD Pipeline: Cloud Build History.