Build and Deploy QueryPal to Cloud Run #33
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # 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)" |