How We Deploy
Terraform + GitHub Actions + Azure Container Apps deployment guide.
How We Deploy
echo ships three containers (docs, server, agent). Infrastructure lives under packages/terraform, images are produced by GitHub Actions, and Azure Container Apps hosts each workload. This page replaces the old packages/docs/DEPLOYMENT.md summary and walks through the process chronologically.
1. Architecture and prerequisites
- Containers:
echo-docs,echo-server,agent. - Azure resources: dedicated Container Apps environment per stage (
echo-dev-rg,echo-prod-rg), PostgreSQL Flexible Server, and an Azure Container Registry shared by both. - Domains: dev endpoints live on
dev-*.echo.onenine.ca, prod on*.echo.onenine.ca(see Custom Domains). - Tools required: Azure CLI, Terraform ≥ 1.6, access to the GitHub repository, and credentials stored as described in GitHub Secrets).
2. Build artifacts
Each package has its own Dockerfile:
apps/docs/Dockerfile– Next.js/Fumadocs static output (next build+ standalone server).packages/server/Dockerfile– Express API with pnpm + Drizzle migrations baked in.packages/agent/Dockerfile– Python runtime with uv/poetry lock (seeuv.lock).
GitHub Actions build these images on every push to main, tag them with the commit SHA, and push them to Azure Container Registry (see GitHub Secrets for required credentials).
3. Terraform environments
Directory layout:
packages/terraform/developmentpackages/terraform/production- Shared modules under
packages/terraform/modules/{docs,server,agent}
Each environment declares the same resources:
| Resource | Purpose |
|---|---|
| Resource Group | Namespace for all assets. |
| Container Registry | Stores Docker images used by Container Apps and the migration job. |
| Azure PostgreSQL Flexible Server | Backing store for Express. Connection string is exported for GitHub Secrets. |
| Container Apps Environment | Shared infrastructure for the 3 services. |
Container Apps (echo-docs, echo-server, agent) | Run the built images with secrets wired in. |
Apply steps
cd packages/terraform/development
terraform init
terraform apply -var="image_tag=sha-abcdef"Use the same process for production, but be mindful that the GitHub workflow gates prod deploys behind a manual approval.
4. GitHub Actions workflows
- Build & push – triggered on every
mainpush, produces Docker images and uploads artifacts that subsequent jobs reuse. - Terraform deploy (dev) – pulls the latest image tag, runs
pnpm db:migratein an Azure Container Instance (seeMIGRATION_SETUP.md), and then updates the Container Apps rev. - Terraform deploy (prod) – same steps, but manual. You must type “production” to confirm.
Secrets referenced in these workflows live in GitHub Secrets.
5. Database migrations
Before each Container App revision rolls out, the workflow:
- Starts a temporary Azure Container Instance with the freshly built
packages/serverimage. - Runs
pnpm db:migrate(wrapper around Drizzle’smigrate-with-rollbackscript). - Aborts the deployment and sends a Slack alert if migrations fail (
SLACK_WEBHOOK_URL).
Manual rollback commands live in MIGRATION_SETUP.md. Locally you can mimic the same behavior with pnpm db:migrate and pnpm db:rollback -- --count=1 --confirm.
6. Releasing a single package
Need to redeploy only the agent or server? Terraform lets you target modules:
cd packages/terraform/development
terraform plan -target=module.agent -var="image_tag=sha-latest"
terraform apply -target=module.agent -var="image_tag=sha-latest"This updates just one Container App using the specified image tag.
7. Verification
- Docs – served from
echo-docsContainer App and locked behind the middleware inapps/docs/middleware.ts; setDOCS_BASIC_AUTH_USERandDOCS_BASIC_AUTH_PASSsecrets on the app before exposing it publicly. - Server –
GET https://<env-domain>/health. - Agent – check LiveKit logs for worker startup; simulate inbound SIP calls.
- Database – verify
drizzle_migrationstable contains the new entries.
Follow this order: build → terraform plan/apply → watch GitHub Actions → verify health endpoints. When you need more detail about the CI/CD pieces or infrastructure, jump to Auto-Deployment Flow, GitHub Secrets, and Custom Domains.