Deployment
The deploy stage provisions infrastructure via Terraform and deploys container images to Azure Container Apps. Each application deploys in its own stage with lockBehavior: sequential to prevent concurrent deployments to the same environment.
Deployment Flow
Terraform
Each container app has its own Terraform configuration in azure/infra/. The deploy step runs:
- Install -- installs the Terraform CLI
- Init -- initializes the backend (Azure Storage Account)
- Apply -- applies the plan created in the
plan_releasestage
Infrastructure and application code are deployed together. This means environment variables, replica scaling, domain configuration, and feature flags can all be changed in the same PR as the application code.
Why Terraform for deployments?
Terraform manages the full Container App configuration alongside the application image. This coupling ensures that infrastructure changes (e.g., adding an env var for a new feature flag) ship with the code that uses them, all in one PR.
Container Apps
The following applications deploy as Azure Container Apps:
- Web (per site: feyenoord, de-kuip)
- API
- Match Gateway
- API Gateway
- GraphQL Router
Each deployment is verified after apply.
Deployment Verification
After Terraform applies, the pipeline runs cicd/scripts/verify-container-app-deployment.sh. This script polls the Container App for a healthy state using exponential backoff:
- Initial delay: 5 seconds
- Maximum delay: 30 seconds
- Maximum retries: 12
The script checks:
- Container App provisioning state
- Active revision status
- Running replica count
- Revision health state
If the deployment fails verification after all retries, the pipeline fails.
CDN Assets
Web application static assets are uploaded to Azure Blob Storage during the build stage, not during deploy. See Docker Builds for details.
The CDN architecture:
| Environment | Storage Account | CDN Domain |
|---|---|---|
| TST | feyewebsitestestcdnst | cdn-tst.feyenoord.com |
| ACC | feyewebsitesacccdnst | cdn-acc.feyenoord.com |
| PRD | feyewebsitesprodcdnst | cdn.feyenoord.com |
Cloudflare routes CDN domain requests to the corresponding Azure Blob Storage container. Next.js content-hashed filenames ensure assets from multiple deployments coexist safely in the same storage container.
Static Web Apps
Two applications deploy as Azure Static Web Apps (not Container Apps):
- Sanity Studio -- deployed with a deploy token, one build per environment
- Storybook -- deployed to TST only
These use the deploy-static-web-app.yaml step template and do not require Terraform.
Post-Deployment Steps
API
After API deployment:
- Algolia reindex -- triggers index rebuilds for all tenant/language combinations (feyenoord + de-kuip, nl + en)
- App Insights annotation -- creates a release annotation in Application Insights
All Container Apps
After each container app deployment:
- App Insights annotation -- records the release in Application Insights with the format
<app> <branch>-<buildId>
Sequential Locking
All deploy stages use lockBehavior: sequential. If two pipelines try to deploy the same app to the same environment concurrently, the second one queues and waits for the first to complete. This prevents deployment conflicts and Terraform state locks.