Streamlining Continuous Deployment: Azure Container Registry with Web Apps
Keeping containerized web apps up-to-date means more than just automating image builds—it demands a secure, traceable, and minimal-latency path from code commit to live deployment. Azure offers a native integration between Container Registry (ACR) and Web Apps that compresses the traditional CI/CD pipeline, provided you’re aware of its operational nuances.
ACR ↔ Web Apps: Direct Wiring & Its Benefits
Why bother gluing together multiple services when Azure's first-party integration can pull container images directly from ACR to your Web App? This path:
- Removes intermediary artifact repositories and opaque custom scripts
- Enables rollback via Docker tags
- Offers authentication via either basic credentials or managed identity
- Supports private registries with RBAC controls
However, it’s essential to treat the “magic” as a network call under the hood—meaning failures or lags in pulling images from ACR may delay startup or redeployments. Audit container pull logs if startup time is abnormally long (Diagnose and solve problems > Container issues
in the Azure portal).
Walkthrough: Automating Deployments from ACR
The process in production environments requires strict versioning, credential management, and error handling. Assumptions:
- Docker v20.10.x+, Azure CLI v2.55+, and an active Azure tenant.
- Example resource names used throughout—replace with your own to avoid collisions.
1. Provision the Container Registry
az acr create \
--resource-group myResourceGroup \
--name myUniqueACRName \
--sku Basic \
--location westeurope
Note: SKU ‘Standard’ is preferred if you need geo-replication or advanced logging.
2. Build, Tag, Push
Working directory contains a valid Dockerfile:
az acr login --name myUniqueACRName
docker build -t myapp:v1.2.3 .
docker tag myapp:v1.2.3 myuniqueacrname.azurecr.io/myapp:v1.2.3
docker push myuniqueacrname.azurecr.io/myapp:v1.2.3
Use semantic versioning in tags; avoid ‘latest’ outside of dev/test branches. A rollback simply involves switching the Web App's configured tag.
3. Deploy the App Service (Linux Example)
az appservice plan create \
--name myAppServicePlan \
--resource-group myResourceGroup \
--sku B1 \
--is-linux
az webapp create \
--resource-group myResourceGroup \
--plan myAppServicePlan \
--name myWebAppName \
--deployment-container-image-name myuniqueacrname.azurecr.io/myapp:v1.2.3
4. Secure Connection to Private ACR
With Username/Password (Legacy Pattern)
az acr credential show --name myUniqueACRName
# Copy username/password
az webapp config container set \
--resource-group myResourceGroup \
--name myWebAppName \
--docker-custom-image-name myuniqueacrname.azurecr.io/myapp:v1.2.3 \
--docker-registry-server-url https://myuniqueacrname.azurecr.io \
--docker-registry-server-user <username> \
--docker-registry-server-password <password>
Known issue: Credentials must be rotated manually for security compliance.
With System-Assigned Managed Identity (Preferred in Production)
# Enable identity if not already enabled
az webapp identity assign \
--resource-group myResourceGroup \
--name myWebAppName
WEBAPP_ID=$(az webapp show -n myWebAppName -g myResourceGroup --query identity.principalId -o tsv)
REGISTRY_ID=$(az acr show -n myUniqueACRName -g myResourceGroup --query id -o tsv)
az role assignment create \
--assignee $WEBAPP_ID \
--role acrpull \
--scope $REGISTRY_ID
az webapp config container set \
--resource-group myResourceGroup \
--name myWebAppName \
--docker-custom-image-name myuniqueacrname.azurecr.io/myapp:v1.2.3
# Registry URL optional if image follows canonical naming
Note: Managed Identity + ‘AcrPull’ role = zero hardcoded secrets, integrates cleanly with Azure policy auditing.
Triggering Continuous Deployment
Unlike Azure Functions or App Service for Git, there’s no built-in Azure toggle for “auto-refresh on new image.” Two industry patterns prevail:
Webhook-Driven Redeploy
- Configure an ACR webhook to POST on push:
az acr webhook create \ --registry myUniqueACRName \ --name webappHook \ --uri "https://<logic-or-function-app-URL>/api/RestartWebApp" \ --actions push
- The endpoint (Logic App or Azure Function) calls:
POST https://management.azure.com/subscriptions/<subId>/resourceGroups/<rg>/providers/Microsoft.Web/sites/<name>/restart?api-version=2022-03-01 Authorization: Bearer <token>
- Requires managed identity or app registration with sufficient permissions.
- Log HTTP 409 errors if restart collides with a deployment in progress.
Pipeline-Driven (Azure DevOps or GitHub Actions)
- CI pipeline builds/tag/pushes the container
- CD step calls
az webapp config container set ...
or ARM/Bicep deployment to update the image tag.- Enables deployment gating, test slot swaps, and approval workflows.
Non-obvious tip: For rapid rollback, keep prior image tags in ACR (don’t prune aggressively) and script az webapp config container set ...
with a known-good tag.
Advanced: Slot Deployment & Staging
App Service supports deployment slots:
- Deploy the next image to a “staging” slot.
- Run automated health checks.
- Swap to production if probes pass.
This reduces downtime, although there’s a brief window for cold start latency post-swap. If alwaysOn
isn’t enabled, first requests may encounter 502 errors during cold container initialization.
Operational Gotchas & Logs
-
Container startup failures: Check App Service logs:
2024-06-11T07:57:23.918Z ERROR - Container myuniqueacrname.azurecr.io/myapp failed to start. Exit code: 137
Common causes include insufficient CPU/memory in the App Service plan or missing environment variables. Increase plan size or adjust app settings as required.
-
Login throttling: ACR may rate-limit pulls if you misconfigure credentials or use too many simultaneous deployments.
-
Manual restart is sometimes needed after updating secrets or configuration—not just pushing a new image.
Summary Table
Approach | Security | Complexity | Typical Use |
---|---|---|---|
Username/Password | Lower | Low | Demo / PoC |
Managed Identity | High | Medium | Production workloads |
Webhook-triggered | Variable | Medium | Light auto-deploy |
Pipeline-driven | High | High | Regulated environments |
Miscellaneous
- Use diagnostic settings to export App Service and ACR logs to Log Analytics for centralized monitoring.
- Pair Container Apps with ACR if you require granular scaling or want to avoid some App Service cold start issues.
- The method above is not perfect—there’s no native out-of-the-box blue/green deploy with traffic splitting, but combining slots and external monitoring gets close.
Tags: #Azure #Containers #ContinuousDeployment #DevOps #WebApps #AzureContainerRegistry