Research: Azure Container Apps Deployment Labels vs Multiple Revisions¶
Reference: https://learn.microsoft.com/en-us/azure/container-apps/deployment-labels
Context¶
We currently implement blue/green deployments using activeRevisionsMode: Multiple — the workflow manually labels revisions, shifts traffic via az containerapp ingress traffic set, smoke-tests, and deactivates the old revision. Azure has since introduced a third revisions mode: Deployment Labels (revisions-mode: labels), which is purpose-built for this pattern.
This document compares the two approaches and outlines a migration plan if we decide to switch.
Current approach — Multiple revisions mode¶
How it works:
- Bicep deploys a new revision with
revisionSuffix: green-<sha>-{be|fe|ui} - Workflow locates the green revision by suffix
- Bootstraps
bluelabel on first deploy (no existing label) - Labels green revision, smoke-tests via direct FQDN
- Shifts traffic:
green=100 blue=0 - Promotes green → blue label
- Deactivates old revision explicitly
Benefits:
- Already implemented and merged
- Smoke-test before cutover is explicit and controllable
- Full control over traffic percentages at every step
- No dependency on a newer Azure API feature (better availability across regions/preview status)
Drawbacks:
- Bootstrap problem: first deploy requires special-casing when no
bluelabel exists yet - Old revision cleanup is manual — a workflow bug could leave stale revisions running and incurring cost
- Traffic shift logic is ~60 lines of bash across three apps — complex and fragile
- Rollback is a separate workflow job that must locate the blue-labelled revision and shift traffic back manually
az containerapp ingress traffic setis a full replacement call — easy to misconfigure weights
Alternative — Deployment Labels mode¶
How it works:
- Bicep sets
activeRevisionsMode: Labels - Each deploy calls
az containerapp update --target-label production(orstage) - Azure automatically creates a new revision, assigns it the label, and shuts down the previous revision that was on that label
- Rollback:
az containerapp label-history show+ reassign label to any prior revision
Benefits:
- Automatic revision lifecycle: Azure deactivates revisions no longer referenced by any label — no manual cleanup, no cost leakage from stale revisions
- Rollback is native: label history is built in, no custom workflow job needed
- Simpler workflow:
az containerapp update --target-label <label>replaces ~60 lines of bash - No bootstrap problem: Azure manages label creation and promotion
- Audit trail: full label history queryable via CLI
Drawbacks:
- Smoke-test before cutover is not built in — traffic shifts immediately when the label is reassigned; we would need to deploy to a
stagelabel first, smoke-test, then reassignproductionto that revision (two-step, still manageable) - Newer feature — may have regional availability or API maturity constraints worth validating
- Requires changing
activeRevisionsModein Bicep fromMultipletoLabels— ARM will reject a direct in-place change; needs a careful migration (deactivate old revisions first) --target-labelis not yet supported in all Bicep resource API versions — would need to verify the currentMicrosoft.App/containerAppsAPI version supports it, or manage via CLI post-deploy
Side-by-side comparison¶
| Dimension | Multiple revisions (current) | Deployment Labels |
|---|---|---|
| Revision cleanup | Manual (az containerapp revision deactivate) |
Automatic |
| Rollback | Custom workflow job, label reassignment via bash | Built-in label history + az containerapp revision label add |
| Traffic shift | Manual ingress traffic set with weight arithmetic |
Implicit on label reassignment |
| Smoke test before cutover | Yes — built into workflow | Requires two-label strategy (stage → production) |
| Bootstrap complexity | First-deploy special-case required | None |
| Workflow complexity | ~60 lines bash per app | ~5 lines per app |
| Bicep change required | None (already deployed) | activeRevisionsMode: 'Labels' — breaking change, needs migration |
| Feature maturity | GA | GA as of 2025 — verify northeurope/westeurope availability |
Migration plan (if approved)¶
Phase 1 — Validate (no code changes)¶
- [ ] Confirm
revisions-mode: labelsis available in westeurope and northeurope viaaz provider show - [ ] Confirm current Bicep API version (
2024-03-01or later) supportsactiveRevisionsMode: 'Labels' - [ ] Review whether
--target-labelis expressible in Bicep or CLI-only
Phase 2 — Bicep changes¶
- [ ] Change
activeRevisionsMode: 'Multiple'→'Labels'ininfra/modules/container_apps.bicepfor all three apps - [ ] Remove
revisionSuffixparameter from all three app templates (Azure generates revision names) - [ ] Remove
revision_suffixparam fromcontainer_apps.bicepandmain.bicep - [ ] Remove
revision_suffixfrom both bicepparam files
Phase 3 — Workflow changes (deploy-application.yml)¶
- [ ] Replace blue/green traffic shift bash function with
az containerapp update --target-label production - [ ] Add a
stagelabel step before cutover: deploy tostage, smoke-test, then reassignproduction - [ ] Remove rollback job (replace with
az containerapp revision label add --label production --revision <sha>one-liner) - [ ] Remove
revision_suffixinput and all references
Phase 4 — Migration execution (prod)¶
- [ ] Deploy dev first; verify label history appears, old revisions auto-deactivate
- [ ] Confirm rollback works:
az containerapp label-history show+ label reassignment - [ ] Deploy prod
Phase 5 — Cleanup¶
- [ ] Remove
handoff-blue-green.mdandplan-blue-green.mdstale sections - [ ] Update
MEMORY.mddeployment flow notes
Recommendation¶
Do not migrate now. The current implementation works and is newly merged. The primary gains from labels mode are automatic cleanup and simpler rollback — real quality-of-life improvements but not blockers. Revisit after the v0.17.0-alpha release is stable in prod. At that point Phase 1 validation takes ~30 minutes and will confirm whether the migration is straightforward.