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 to main or via manual dispatch. It builds the docs, server, and agent Dockerfiles, tags them YYYY.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, runs pnpm db:migrate in 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 requested image_tag exists, makes you type production for confirmation, runs migrations, then applies Terraform to the prod workspace.

Required components

  1. 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 run terraform plan/apply.
  2. Azure credentials – service principal (or OIDC) with Contributor rights. Its IDs live in GitHub secrets (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_SUBSCRIPTION_ID, AZURE_TENANT_ID).
  3. Container registry credentialsAZURE_REGISTRY_NAME, AZURE_REGISTRY_USERNAME, AZURE_REGISTRY_PASSWORD so workflows can push/pull images.
  4. Environment-specific secrets – database passwords, LiveKit/Twilio/OpenAI keys, and storage credentials scoped to development or production. See GitHub Secrets.

Before first deployment

  1. Create backend storagecd packages/terraform && ./setup-backend.sh.
  2. Initialize Terraform – run terraform init inside packages/terraform/development and .../production.
  3. Apply infraterraform apply in dev, then prod when ready. This creates Container Apps, PostgreSQL, the Container Apps environment, and binds custom domains described in Custom Domains.
  4. 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 type production in the confirmation field. Health checks run after Terraform finishes, and the summary links to docs/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 --follow to 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

ErrorFix
Terraform backend not configuredRe-run ./setup-backend.sh, then terraform init -backend-config="key=<env>.tfstate".
Image not found in registryaz acr repository show-tags --name $AZURE_REGISTRY_NAME --repository echo-server.
Authentication failedRegenerate the service principal secret and update GitHub secrets.
State lock timeoutterraform 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.