Azure Container Instances and Container Apps
Containers package applications with their dependencies for consistent deployment. Azure offers multiple container services at different levels of abstraction: Azure Container Instances (ACI) for simple, fast container runs, and Azure Container Apps (ACA) for production microservices with auto-scaling, ingress, and Dapr integration. Choose based on operational complexity and scaling requirements.
Container Services Comparison
| Service | Abstraction | Scaling | Best For |
|---|---|---|---|
| Container Instances | Single container/group | Manual | Batch jobs, CI tasks, simple APIs |
| Container Apps | Managed K8s (abstracted) | KEDA auto-scale | Microservices, event-driven apps |
| App Service (containers) | PaaS | App Service rules | Web apps with container images |
| AKS | Full Kubernetes | HPA, KEDA, CA | Complex orchestration, multi-tenant |
Azure Container Instances (ACI)
ACI runs containers without managing VMs or orchestrators. Containers start in seconds and you pay per second of vCPU and memory.
# Create a single container
az container create \
--resource-group rg-batch-prod \
--name aci-data-processor \
--image mcr.microsoft.com/azuredocs/aci-helloworld \
--cpu 1 \
--memory 1.5 \
--ports 80 \
--dns-name-label aci-processor-unique \
--location eastus
# Get container IP and FQDN
az container show \
--resource-group rg-batch-prod \
--name aci-data-processor \
--query "{IP:ipAddress.ip, FQDN:ipAddress.fqdn}" -o table
# View container logs
az container logs \
--resource-group rg-batch-prod \
--name aci-data-processor
Container Groups
Run multiple containers in a shared lifecycle (sidecar pattern):
az container create \
--resource-group rg-batch-prod \
--name aci-app-with-sidecar \
--file container-group.yaml \
--location eastus
container-group.yaml:
apiVersion: 2019-12-01
location: eastus
name: aci-app-with-sidecar
properties:
containers:
- name: app
properties:
image: myregistry.azurecr.io/web-app:v1.0
resources:
requests:
cpu: 1
memoryInGb: 1.5
ports:
- port: 8080
- name: log-collector
properties:
image: fluent/fluent-bit:latest
resources:
requests:
cpu: 0.25
memoryInGb: 0.5
osType: Linux
ipAddress:
type: Public
ports:
- protocol: tcp
port: 8080
imageRegistryCredentials:
- server: myregistry.azurecr.io
username: myregistry
password: <acr-password>
type: Microsoft.ContainerInstance/containerGroups
ACI with Azure Files Volume
az container create \
--resource-group rg-batch-prod \
--name aci-with-volume \
--image myregistry.azurecr.io/batch-job:latest \
--azure-file-volume-account-name stbatchprod001 \
--azure-file-volume-share-name jobdata \
--azure-file-volume-mount-path /data \
--azure-file-volume-account-key "<storage-key>" \
--restart-policy OnFailure
Azure Container Apps (ACA)
Container Apps runs on a managed Kubernetes environment with KEDA-based scaling, built-in ingress, revisions, and Dapr support — without managing clusters.
# Install Container Apps extension
az extension add --name containerapp --upgrade
# Register providers
az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights
# Create Container Apps environment
az containerapp env create \
--name cae-webapp-prod \
--resource-group rg-webapp-prod \
--location eastus
# Deploy a container app
az containerapp create \
--name ca-webapp-api \
--resource-group rg-webapp-prod \
--environment cae-webapp-prod \
--image myregistry.azurecr.io/api:v1.2.0 \
--target-port 8080 \
--ingress external \
--min-replicas 1 \
--max-replicas 10 \
--cpu 0.5 \
--memory 1.0Gi \
--registry-server myregistry.azurecr.io \
--registry-identity system
# Scale based on HTTP concurrent requests
az containerapp update \
--name ca-webapp-api \
--resource-group rg-webapp-prod \
--scale-rule-name http-scaling \
--scale-rule-type http \
--scale-rule-http-concurrency 50
KEDA Scaling Rules
Container Apps supports event-driven scaling beyond HTTP:
| Scale Rule | Trigger | Use Case |
|---|---|---|
| HTTP | Concurrent requests | Web APIs |
| Azure Service Bus | Queue depth | Async processing |
| Azure Storage Queue | Message count | Batch jobs |
| Cron | Schedule | Nightly reports |
| Custom | Prometheus metrics | Any metric source |
# Scale on Service Bus queue depth
az containerapp update \
--name ca-order-processor \
--resource-group rg-webapp-prod \
--scale-rule-name sb-queue \
--scale-rule-type azure-servicebus \
--scale-rule-metadata queueName=orders namespace=sb-webapp-prod messageCount=5 \
--scale-rule-auth connection=service-bus-connection
Revisions and Traffic Splitting
Container Apps supports blue-green and canary deployments via revision management:
# Deploy new revision (creates v2 alongside v1)
az containerapp update \
--name ca-webapp-api \
--resource-group rg-webapp-prod \
--image myregistry.azurecr.io/api:v1.3.0
# Split traffic: 90% v1, 10% v2
az containerapp ingress traffic set \
--name ca-webapp-api \
--resource-group rg-webapp-prod \
--revision-weight ca-webapp-api--v1=90 ca-webapp-api--v2=10
Real-World Scenario: Event-Driven Order Processing
| Component | Service | Configuration |
|---|---|---|
| API gateway | Container App | External ingress, HTTP scaling 1–20 |
| Order processor | Container App | Service Bus queue trigger, 0–50 replicas |
| Report generator | Container Instance | OnFailure restart, Azure Files output |
| Image storage | ACR | Managed identity pull |
| Secrets | Key Vault | Referenced in Container App env vars |
ACI vs Container Apps vs AKS
| Feature | ACI | Container Apps | AKS |
|---|---|---|---|
| Startup time | Seconds | Seconds | Minutes (node provisioning) |
| Scale to zero | No | Yes | With KEDA |
| Multi-container | Container groups | Single container per app | Pods |
| Networking | Public IP or VNet | Built-in ingress + VNet | Full K8s networking |
| Cost model | Per-second vCPU/memory | Per vCPU-second + requests | Node pool hourly |
| Complexity | Minimal | Low-medium | High |
Common Mistakes
- Using ACI for long-running web services — no auto-healing or load balancing; use Container Apps
- No health probes on Container Apps — unhealthy replicas receive traffic
- Pulling from ACR without identity — store credentials in Key Vault, use managed identity
- Ignoring cold start with scale-to-zero — set
min-replicas: 1for latency-sensitive APIs - ACI without restart policy — batch jobs need
--restart-policy OnFailure - Oversized ACI containers — right-size CPU/memory; ACI bills per allocated resources
Troubleshooting
| Issue | Diagnosis | Fix |
|---|---|---|
| ACI stuck Creating | Image pull failure or quota | Check ACR credentials; verify regional vCPU quota |
| Container App not scaling | Scale rule misconfigured | Verify KEDA trigger metadata and auth secret |
| 502 on ingress | App not listening on target-port | Match --target-port to container port |
| ACR pull denied | Missing AcrPull role | Assign managed identity AcrPull on registry |
| ACI OOMKilled | Memory limit too low | Increase --memory; check container logs |
# Check Container App logs
az containerapp logs show \
--name ca-webapp-api \
--resource-group rg-webapp-prod \
--follow
# Check ACI events
az container show \
--resource-group rg-batch-prod \
--name aci-data-processor \
--query "instanceView.events" -o table
Best Practices
- Use ACI for burst/batch workloads, CI agents, and one-off tasks
- Use Container Apps for microservices, APIs, and event-driven processing
- Enable managed identity for ACR pulls and Key Vault secret access
- Configure health probes (liveness/readiness) on Container Apps
- Use revision labels and traffic splitting for safe canary deployments
- Deploy Container Apps environment in a VNet for private backend access
- Monitor with Application Insights and Container Apps built-in metrics
Next: Advanced Networking.