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

  1. Using ACI for long-running web services — no auto-healing or load balancing; use Container Apps
  2. No health probes on Container Apps — unhealthy replicas receive traffic
  3. Pulling from ACR without identity — store credentials in Key Vault, use managed identity
  4. Ignoring cold start with scale-to-zero — set min-replicas: 1 for latency-sensitive APIs
  5. ACI without restart policy — batch jobs need --restart-policy OnFailure
  6. 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.