Deployments
Auto-Deployment Flow
How GitHub Actions builds images, runs migrations, and promotes them across environments.
Auto-Deployment Flow
This article replaces the standalone AUTO_DEPLOY.md file and distills the same procedure into a single runbook.
Pipeline overview
Push to main → Build Docker Images → Deploy to Development
↓
Tag images with version
↓
Manual trigger → Deploy to Production- Build & Push (
.github/workflows/docker-build-push.yml) – kicks off on every push tomainor via manual dispatch. It builds the docs, server, and agent Dockerfiles, tags themYYYY.MM.NN+latest, and pushes to Azure Container Registry. - Development Deploy (
terraform-deploy-dev.yml) – auto-runs after images are available. It grabs the latest tag, runspnpm db:migratein an Azure migration job, applies Terraform, and posts URLs in the job summary. - Production Deploy (
terraform-deploy-prod.yml) – manual only. It validates that the requestedimage_tagexists, makes you typeproductionfor confirmation, runs migrations, then applies Terraform to the prod workspace.
Required components
- Terraform backend – created once via
packages/terraform/setup-backend.sh. Dev/prod state files (development.tfstate,production.tfstate) sit in Azure Blob Storage so Actions can runterraform plan/apply. - Azure credentials – service principal (or OIDC) with
Contributorrights. Its IDs live in GitHub secrets (AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_SUBSCRIPTION_ID,AZURE_TENANT_ID). - Container registry credentials –
AZURE_REGISTRY_NAME,AZURE_REGISTRY_USERNAME,AZURE_REGISTRY_PASSWORDso workflows can push/pull images. - Environment-specific secrets – database passwords, LiveKit/Twilio/OpenAI keys, and storage credentials scoped to
developmentorproduction. See GitHub Secrets.
Before first deployment
- Create backend storage –
cd packages/terraform && ./setup-backend.sh. - Initialize Terraform – run
terraform initinsidepackages/terraform/developmentand.../production. - Apply infra –
terraform applyin dev, then prod when ready. This creates Container Apps, PostgreSQL, the Container Apps environment, and binds custom domains described in Custom Domains. - Seed secrets – populate the GitHub secrets outlined below so the workflows can authenticate.
Using the workflows
- Development (automatic) – push/merge to
main. The workflow builds images, deploys, and prints the URLs (dev-docs.echo.onenine.ca,dev-api.echo.onenine.ca,dev-agent.echo.onenine.ca). - Development (manual) – in Actions, run “Deploy to Development,” choose the tag (or
latest), and fire it off. - Production – after validating dev, run “Deploy to Production,” specify the
image_tag, and typeproductionin the confirmation field. Health checks run after Terraform finishes, and the summary links todocs/api/agent.echo.onenine.ca.
Monitoring and rollback
- Watch workflow logs in GitHub Actions for Terraform output and migration logs.
- Use
az containerapp logs show --name echo-server-{env} --resource-group echo-{env}-rg --followto tail runtime logs. - Roll back by redeploying an older tag via the same workflow or by running Terraform with
-var "image_tag=YYYY.MM.NN".
Troubleshooting cheatsheet
| Error | Fix |
|---|---|
Terraform backend not configured | Re-run ./setup-backend.sh, then terraform init -backend-config="key=<env>.tfstate". |
Image not found in registry | az acr repository show-tags --name $AZURE_REGISTRY_NAME --repository echo-server. |
Authentication failed | Regenerate the service principal secret and update GitHub secrets. |
State lock timeout | terraform force-unlock <lock-id> in the appropriate env folder. |
Keep deployments boring by letting the automation run whenever main changes and reserving production workflow runs for intentional releases.