07 - Revisions and Traffic Splitting¶
Azure Container Apps revisions provide immutable deployment snapshots. Use them for safe releases, canary traffic, and quick rollback.
Infrastructure Context
Service: Container Apps (Consumption) | Network: VNet integrated | VNet: ✅
This tutorial assumes a production-ready Container Apps deployment with a custom VNet, ACR with managed identity pull, and private endpoints for backend services.
flowchart TD
INET[Internet] -->|HTTPS| CA["Container App\nConsumption\nLinux Python 3.11"]
subgraph VNET["VNet 10.0.0.0/16"]
subgraph ENV_SUB["Environment Subnet 10.0.0.0/23\nDelegation: Microsoft.App/environments"]
CAE[Container Apps Environment]
CA
end
subgraph PE_SUB["Private Endpoint Subnet 10.0.2.0/24"]
PE_ACR[PE: ACR]
PE_KV[PE: Key Vault]
PE_ST[PE: Storage]
end
end
PE_ACR --> ACR[Azure Container Registry]
PE_KV --> KV[Key Vault]
PE_ST --> ST[Storage Account]
subgraph DNS[Private DNS Zones]
DNS_ACR[privatelink.azurecr.io]
DNS_KV[privatelink.vaultcore.azure.net]
DNS_ST[privatelink.blob.core.windows.net]
end
PE_ACR -.-> DNS_ACR
PE_KV -.-> DNS_KV
PE_ST -.-> DNS_ST
CA -.->|System-Assigned MI| ENTRA[Microsoft Entra ID]
CAE --> LOG[Log Analytics]
CA --> AI[Application Insights]
style CA fill:#107c10,color:#fff
style VNET fill:#E8F5E9,stroke:#4CAF50
style DNS fill:#E3F2FD Revision Traffic Splitting¶
graph LR
INGRESS[Ingress] -->|90%| V1[Revision v1]
INGRESS -->|10%| V2[Revision v2] Prerequisites¶
- Completed 06 - CI/CD with GitHub Actions
- At least two deployed images/tags
Define promotion criteria before traffic split
Decide in advance which metrics (error rate, latency percentile, saturation) must stay within threshold before increasing canary traffic.
Step-by-step¶
- Set standard variables (reuse Bicep outputs from Step 02)
RG="rg-myapp"
BASE_NAME="myapp"
DEPLOYMENT_NAME="main"
APP_NAME=$(az deployment group show \
--name "$DEPLOYMENT_NAME" \
--resource-group "$RG" \
--query "properties.outputs.containerAppName.value" \
--output tsv)
ENVIRONMENT_NAME=$(az deployment group show \
--name "$DEPLOYMENT_NAME" \
--resource-group "$RG" \
--query "properties.outputs.containerAppEnvName.value" \
--output tsv)
ACR_NAME=$(az deployment group show \
--name "$DEPLOYMENT_NAME" \
--resource-group "$RG" \
--query "properties.outputs.containerRegistryName.value" \
--output tsv)
ACR_LOGIN_SERVER=$(az deployment group show \
--name "$DEPLOYMENT_NAME" \
--resource-group "$RG" \
--query "properties.outputs.containerRegistryLoginServer.value" \
--output tsv)
- Switch to multiple revision mode
???+ example "Expected output"
- Deploy a new version to create a new revision
az acr build --registry "$ACR_NAME" --image "$BASE_NAME:v3" ./app
az containerapp update \
--name "$APP_NAME" \
--resource-group "$RG" \
--image "$ACR_LOGIN_SERVER/$BASE_NAME:v3"
???+ example "Expected output" az acr build takes 1-2 minutes. The az containerapp update returns:
{
"latestRevision": "<your-app-name>--xxxxxxx",
"name": "<your-app-name>",
"provisioningState": "Succeeded"
}
- List revisions and choose targets
az containerapp revision list \
--name "$APP_NAME" \
--resource-group "$RG" \
--query "[].{name:name,active:properties.active,createdTime:properties.createdTime}" \
--output table
???+ example "Expected output"
Name Active CreatedTime
--------------------------------------- -------- -------------------------
<your-app-name>--0000001 True 2024-01-15T10:00:00+00:00
<your-app-name>--0000002 True 2024-01-15T10:15:00+00:00
JSON equivalent (`--output json`):
```json
[
{
"name": "<your-app-name>--0000001",
"active": true,
"createdTime": "2024-01-15T10:00:00+00:00"
},
{
"name": "<your-app-name>--0000002",
"active": true,
"createdTime": "2024-01-15T10:15:00+00:00"
}
]
```
- Apply canary traffic split (90/10)
az containerapp ingress traffic set \
--name "$APP_NAME" \
--resource-group "$RG" \
--revision-weight "<stable-revision>=90" "<canary-revision>=10"
???+ example "Expected output"
[
{
"revisionName": "<your-app-name>--0000001",
"weight": 90
},
{
"revisionName": "<your-app-name>--0000002",
"weight": 10
}
]
Verify applied traffic routing:
???+ example "Expected output"
{
"allowInsecure": false,
"external": true,
"fqdn": "<your-app-name>.<hash>.<region>.azurecontainerapps.io",
"targetPort": 8000,
"transport": "Auto",
"traffic": [
{
"revisionName": "<your-app-name>--0000001",
"weight": 90
},
{
"revisionName": "<your-app-name>--0000002",
"weight": 10
}
]
}
- Rollback instantly if errors increase
az containerapp ingress traffic set \
--name "$APP_NAME" \
--resource-group "$RG" \
--revision-weight "<stable-revision>=100"
???+ example "Expected output"
- Deactivate bad revision after confirmation
az containerapp revision deactivate \
--name "$APP_NAME" \
--resource-group "$RG" \
--revision "<canary-revision>"
???+ example "Expected output"
Operational guidance¶
- Pair canary rollout with telemetry checks (errors, latency, saturation).
- Keep one prior known-good revision for emergency rollback.
- Use KEDA metrics and revision health together for rollout decisions.
Do not leave stale canary revisions active
After rollback or promotion, deactivate obsolete revisions to reduce operational confusion and prevent unintended traffic assignment during future updates.
Advanced Topics¶
- Route traffic by labels for blue/green style releases.
- Combine revisions with Dapr service invocation for progressive migration.
- Automate canary promotion in CI/CD using policy checks.