Skip to content

Build and Deploy QueryPal to Cloud Run #32

Build and Deploy QueryPal to Cloud Run

Build and Deploy QueryPal to Cloud Run #32

# Build and deploy QueryPal to Cloud Run.
# Runs on pushes to the production branch.
#
# Infrastructure changes (VPC connector, Secret Manager, IAM) are managed by
# Terraform in the terraform/ directory and must be applied before first deploy.
name: 'Build and Deploy QueryPal to Cloud Run'
on:
push:
branches:
- 'production'
workflow_dispatch:
env:
PROJECT_ID: 'gen-lang-client-0698668474'
REGION: 'europe-west1'
BACKEND_SERVICE: 'querypal-backend'
FRONTEND_SERVICE: 'querypal-frontend'
WORKLOAD_IDENTITY_PROVIDER: 'projects/874216619692/locations/global/workloadIdentityPools/github/providers/querypal'
# Short name of the Cloud Run SA and VPC connector created by Terraform.
# The full SA email is constructed inline in flags using ${{ env.PROJECT_ID }}
# because GitHub Actions does not interpolate env vars inside the env: block.
CLOUD_RUN_SA_NAME: 'querypal-cloudrun-sa'
VPC_CONNECTOR: 'querypal-vpc-connector'
jobs:
deploy:
runs-on: 'ubuntu-latest'
permissions:
contents: 'read'
id-token: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332' # actions/checkout@v4
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@f112390a2df9932162083945e46d439060d66ec2' # google-github-actions/auth@v2
with:
workload_identity_provider: '${{ env.WORKLOAD_IDENTITY_PROVIDER }}'
service_account: 'github-actions@${{ env.PROJECT_ID }}.iam.gserviceaccount.com'
- name: 'Set up Cloud SDK'
uses: 'google-github-actions/setup-gcloud@98ddc00a17442e89a24bbf282954a3b65ce6d200' # google-github-actions/setup-gcloud@v2
- name: 'Configure Docker for GCR'
run: gcloud auth configure-docker --quiet
# ── Backend ──────────────────────────────────────────────────────────────
- name: 'Build and Push Backend Container'
run: |-
cd backend
DOCKER_TAG="gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_SERVICE }}:${{ github.sha }}"
docker build --tag "${DOCKER_TAG}" --platform linux/amd64 .
docker push "${DOCKER_TAG}"
- id: 'deploy-backend'
name: 'Deploy Backend to Cloud Run'
uses: 'google-github-actions/deploy-cloudrun@33553064113a37d688aa6937bacbdc481580be17' # google-github-actions/deploy-cloudrun@v2
with:
service: '${{ env.BACKEND_SERVICE }}'
region: '${{ env.REGION }}'
image: 'gcr.io/${{ env.PROJECT_ID }}/${{ env.BACKEND_SERVICE }}:${{ github.sha }}'
# Non-secret runtime configuration only.
env_vars: |
ENVIRONMENT=production
ARM_SCOPE=https://management.azure.com/.default
DB_NAME=querypal
DB_UNIX_SOCKET=/cloudsql/${{ env.PROJECT_ID }}:${{ env.REGION }}:querypal-db
# Sensitive values are read directly from Secret Manager at runtime.
# Secret must exist before first deploy (created by terraform/secrets.tf).
secrets: |
AZURE_TENANT_ID=querypal-azure-tenant-id:latest
AZURE_CLIENT_ID=querypal-azure-client-id:latest
AZURE_CLIENT_SECRET=querypal-azure-client-secret:latest
GEMINI_API_KEY=querypal-gemini-api-key:latest
DB_USER=querypal-db-user:latest
DB_PASS=querypal-db-pass:latest
flags: |
--port=8000
--service-account=${{ env.CLOUD_RUN_SA_NAME }}@${{ env.PROJECT_ID }}.iam.gserviceaccount.com
--add-cloudsql-instances=${{ env.PROJECT_ID }}:${{ env.REGION }}:querypal-db
--vpc-connector=${{ env.VPC_CONNECTOR }}
--vpc-egress=private-ranges-only
--ingress=internal
--allow-unauthenticated
# ── Frontend ─────────────────────────────────────────────────────────────
- name: 'Build and Push Frontend Container'
run: |-
cd frontend
DOCKER_TAG="gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_SERVICE }}:${{ github.sha }}"
# VITE_API_BASE_URL=/api tells the React app to send all API calls to
# the /api/* path on its own origin instead of a full backend URL.
# Nginx then proxies those requests to the internal backend service.
docker build --tag "${DOCKER_TAG}" --platform linux/amd64 \
--build-arg VITE_API_BASE_URL=/api \
--build-arg VITE_AZURE_REDIRECT_URI=https://querypal.virtonomy.io \
.
docker push "${DOCKER_TAG}"
- id: 'deploy-frontend'
name: 'Deploy Frontend to Cloud Run'
uses: 'google-github-actions/deploy-cloudrun@33553064113a37d688aa6937bacbdc481580be17' # google-github-actions/deploy-cloudrun@v2
with:
service: '${{ env.FRONTEND_SERVICE }}'
region: '${{ env.REGION }}'
image: 'gcr.io/${{ env.PROJECT_ID }}/${{ env.FRONTEND_SERVICE }}:${{ github.sha }}'
# BACKEND_URL is the internal Cloud Run URL; nginx uses it at runtime to
# proxy /api/* requests to the backend (which is not publicly reachable).
env_vars: |
BACKEND_URL=${{ steps.deploy-backend.outputs.url }}
flags: |
--port=4000
--service-account=${{ env.CLOUD_RUN_SA_NAME }}@${{ env.PROJECT_ID }}.iam.gserviceaccount.com
--vpc-connector=${{ env.VPC_CONNECTOR }}
--vpc-egress=all-traffic
--ingress=all
--allow-unauthenticated
# ── Summary ───────────────────────────────────────────────────────────────
- name: 'Show deployment URLs'
run: |-
echo "Frontend URL: ${{ steps.deploy-frontend.outputs.url }}"
echo "Backend URL: ${{ steps.deploy-backend.outputs.url }} (internal only)"