Azure Container Apps (ACA) represents Microsoft’s vision for a serverless container platform that sits between Azure Functions and Azure Kubernetes Service in complexity. Now Generally Available, ACA provides a fully managed environment for deploying containerized applications with built-in support for KEDA autoscaling, Dapr integration, and seamless CI/CD. Having deployed multiple production workloads on ACA, this guide shares everything you need to know for enterprise adoption.
Architectural Overview
Azure Container Apps runs on an AKS foundation but abstracts away all Kubernetes complexity. You never interact with Deployments, Services, or Ingress resources. Instead, you work with Container Apps, Environments, and Revisions.
flowchart TB
subgraph Environment ["Container Apps Environment"]
subgraph VNET ["Virtual Network"]
App1["Container App: API"]
App2["Container App: Worker"]
App3["Container App: Frontend"]
App1 -- Dapr --> App2
App3 --> App1
end
Ingress["Managed Ingress (Envoy)"]
KEDA["KEDA Autoscaler"]
Dapr["Dapr Sidecar Runtime"]
end
Users["Internet Users"] --> Ingress
Ingress --> App3
style Environment fill:#E1F5FE,stroke:#0277BD
style KEDA fill:#C8E6C9,stroke:#2E7D32
Creating a Container Apps Environment
The Environment is the isolation boundary. All apps within an environment share the same virtual network and logging configuration:
param location string = resourceGroup().location
param environmentName string = 'myapp-env'
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
name: '${environmentName}-logs'
location: location
properties: {
sku: { name: 'PerGB2018' }
retentionInDays: 30
}
}
resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-10-01' = {
name: environmentName
location: location
properties: {
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalytics.properties.customerId
sharedKey: logAnalytics.listKeys().primarySharedKey
}
}
vnetConfiguration: {
internal: false
infrastructureSubnetId: vnet::infraSubnet.id
}
zoneRedundant: true // Enable for production workloads
}
}
Deploying a Container App
Here is a complete example of deploying a .NET 6 API with autoscaling, secrets, and managed identity:
resource containerApp 'Microsoft.App/containerApps@2022-10-01' = {
name: 'order-api'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
managedEnvironmentId: containerAppsEnvironment.id
configuration: {
activeRevisionsMode: 'Multiple' // Blue-green deployments
ingress: {
external: true
targetPort: 80
transport: 'http'
traffic: [
{ revisionName: 'order-api--v1', weight: 90 }
{ revisionName: 'order-api--v2', weight: 10 }
]
}
secrets: [
{
name: 'db-connection-string'
keyVaultUrl: 'https://myvault.vault.azure.net/secrets/DbConnectionString'
identity: 'system'
}
]
registries: [
{
server: 'myacr.azurecr.io'
identity: 'system'
}
]
}
template: {
containers: [
{
name: 'api'
image: 'myacr.azurecr.io/order-api:v1.2.0'
resources: {
cpu: json('0.5')
memory: '1Gi'
}
env: [
{ name: 'ASPNETCORE_ENVIRONMENT', value: 'Production' }
{ name: 'ConnectionStrings__Database', secretRef: 'db-connection-string' }
]
}
]
scale: {
minReplicas: 1
maxReplicas: 30
rules: [
{
name: 'http-scaling'
http: {
metadata: {
concurrentRequests: '100'
}
}
}
{
name: 'queue-scaling'
custom: {
type: 'azure-queue'
metadata: {
queueName: 'orders'
queueLength: '10'
accountName: 'mystorageaccount'
}
auth: [
{ secretRef: 'storage-connection', triggerParameter: 'connection' }
]
}
}
]
}
}
}
}
Dapr Integration
ACA has first-class Dapr support. Enable it to get service-to-service invocation, state management, and pub/sub without changing your code:
# component.yaml - Azure Service Bus pub/sub
componentType: pubsub.azure.servicebus.topics
version: v1
metadata:
- name: connectionString
secretRef: servicebus-connection
- name: consumerID
value: order-processor
// Your code - no SDK references, just HTTP
await daprClient.PublishEventAsync("pubsub", "orders", orderData);
// Receiving side
[HttpPost("/orders")]
public async Task HandleOrder([FromBody] CloudEvent<Order> order)
{
// Process order
}
Blue-Green Deployments
ACA’s revision management makes blue-green deployments trivial:
# Deploy new revision
az containerapp update -n order-api -g mygroup \
--image myacr.azurecr.io/order-api:v1.3.0
# Route 10% traffic to new revision
az containerapp ingress traffic set -n order-api -g mygroup \
--revision-weight order-api--v12=90 order-api--v13=10
# If healthy, shift all traffic
az containerapp ingress traffic set -n order-api -g mygroup \
--revision-weight order-api--v13=100
Networking and Security
For production workloads, deploy into a VNET with private ingress:
- Internal Ingress: Apps only accessible within VNET
- Private Endpoints: Connect to Azure SQL, Cosmos DB without public IPs
- NSGs: Control traffic flow between subnets
- Managed Identity: Authenticate to Azure services without secrets
Key Takeaways
- ACA is ideal for microservices that don’t need raw Kubernetes access
- Enable Zone Redundancy for production workloads
- Use Managed Identity for zero-secret deployments
- Leverage KEDA scalers for queue-based workloads
- Dapr integration simplifies service mesh patterns
- Traffic splitting enables safe blue-green deployments
Discover more from C4: Container, Code, Cloud & Context
Subscribe to get the latest posts sent to your email.