Fundamentação Teórica: Provision a container by using Azure Container Apps
1. Intuição Inicial​
Nos módulos anteriores, vimos dois extremos do spectrum de containers no Azure: o ACI (execução simples, sem gerenciamento, ideal para tarefas pontuais) e o AKS (orquestração completa com Kubernetes, ideal para arquiteturas complexas em produção). O Azure Container Apps (ACA) ocupa o espaço entre eles.
Pense assim: o ACI é como alugar um quarto de hotel por uma noite. O AKS é como gerenciar um condomÃnio completo, você tem controle total mas precisa cuidar de tudo. O Azure Container Apps é como morar em um serviço de co-living: você tem seu espaço independente, não precisa se preocupar com a infraestrutura do prédio, pode receber mais hóspedes automaticamente quando necessário, e paga apenas pelo que usa.
O ACA é construÃdo sobre Kubernetes e KEDA (Kubernetes Event-Driven Autoscaling) internamente, mas você nunca precisa interagir com esses sistemas diretamente. O Azure gerencia todo o cluster Kubernetes subjacente. Você apenas define: "minha aplicação é este container, deve escalar de 0 a 10 réplicas baseado no número de requisições HTTP por segundo".
2. Contexto​
O ACA foi lançado pela Microsoft como resposta ao crescimento de arquiteturas de microsserviços e event-driven que precisam de scaling automático sofisticado (incluindo scale-to-zero) sem a complexidade operacional do Kubernetes.
O ACA é construÃdo sobre tecnologias open source: Kubernetes para orquestração, KEDA para autoscaling baseado em eventos, Dapr para comunicação entre microsserviços, e Envoy como proxy de serviço. Você se beneficia de tudo isso sem precisar configurar nada manualmente.
3. Construção dos Conceitos​
3.1 Hierarquia de Recursos: Environment, App, Revision​
Container Apps Environment: o contêiner lógico que agrupa múltiplos Container Apps. Todos os apps dentro de um environment compartilham a mesma VNet, o mesmo Log Analytics workspace, e podem se comunicar entre si via DNS interno. Um environment corresponde a um cluster Kubernetes gerenciado pelo Azure.
Container App: a aplicação em si. Define a imagem do container, variáveis de ambiente, escalamento, ingress e outras configurações. Uma Container App pode ter múltiplas Revisions ativas simultaneamente.
Revision: uma versão imutável de uma Container App. Cada vez que você atualiza a configuração que afeta o container (imagem, variáveis de ambiente, CPU/memória), uma nova revision é criada. Você pode distribuir o tráfego entre revisões para fazer canary deployments ou blue/green.
Replica: uma instância em execução de uma revision. O autoscaler aumenta ou diminui o número de réplicas baseado nas regras configuradas.
3.2 Revision Modes​
O comportamento das revisions depende do Revision Mode:
| Modo | Comportamento | Uso |
|---|---|---|
| Single (padrão) | Apenas uma revision ativa por vez. Nova revision substitui a antiga automaticamente. | Aplicações simples sem necessidade de A/B testing |
| Multiple | Múltiplas revisions ativas simultaneamente. Tráfego pode ser dividido entre elas. | Canary deployments, A/B testing, blue/green |
3.3 Ingress: Acesso ao Container App​
O Ingress controla como a Container App é acessÃvel:
| Tipo | Descrição | URL gerada |
|---|---|---|
| External (enabled) | AcessÃvel da internet via HTTPS | https://minha-api.<hash>.brazilsouth.azurecontainerapps.io |
| Internal (enabled) | AcessÃvel apenas dentro do environment | https://minha-api (nome curto) |
| Disabled | Sem acesso de rede (jobs, processadores) | Nenhuma URL |
O ACA gerencia automaticamente:
- Certificado TLS (HTTPS habilitado por padrão para ingress externo)
- Load balancing entre réplicas
- Custom domains (com seu próprio certificado ou managed certificate gratuito)
3.4 Autoscaling com KEDA​
O autoscaling do ACA é baseado em scalers (gatilhos de escala). O mais importante para o AZ-104:
| Tipo de scaler | O que monitora | Exemplo |
|---|---|---|
| HTTP | Requisições HTTP simultâneas | Escalar quando > 10 req concorrentes por réplica |
| CPU | Uso de CPU | Escalar quando CPU > 70% |
| Memory | Uso de memória | Escalar quando memória > 80% |
| Azure Service Bus | Mensagens na fila | 1 réplica por mensagem na fila |
| Azure Storage Queue | Mensagens na fila | 1 réplica a cada 5 mensagens |
| Custom | Qualquer métrica via KEDA | Qualquer fonte suportada pelo KEDA |
Scale-to-zero: quando não há tráfego ou mensagens na fila, o número de réplicas pode chegar a zero. O container não consome CPU nem memória, e você não paga por computação. Quando uma nova requisição chega, o ACA inicia uma réplica automaticamente (com latência de cold start, geralmente segundos).
O intervalo de escala é definido por minReplicas e maxReplicas:
scale:
minReplicas: 0 # scale-to-zero ativo
maxReplicas: 10 # máximo de 10 réplicas
rules:
- name: http-rule
http:
metadata:
concurrentRequests: "10" # 1 réplica para cada 10 req concorrentes
3.5 Jobs vs. Apps​
Além de Container Apps (serviços de longa duração), o ACA suporta Container Apps Jobs: execuções que terminam após completar uma tarefa, similar ao ACI com restartPolicy: Never.
| Tipo | Duração | Trigger | Billing |
|---|---|---|---|
| Container App | ContÃnua | Tráfego / mensagens | Por vCPU/s e GB/s usados |
| Container App Job | Finita (termina) | Manual, Scheduled (cron), Event-driven | Por execução |
4. Visão Estrutural​
5. Funcionamento na Prática​
Ciclo de Vida de um Deploy​
Comportamentos Importantes e Não Óbvios​
Revision names são gerados automaticamente: cada nova revision recebe um nome no formato <app-name>--<sufixo-aleatorio>. Você pode especificar um sufixo customizado: --revision-suffix v2-release.
Scale-to-zero tem cold start: quando há 0 réplicas e chega uma requisição, o ACA precisa iniciar uma nova réplica antes de responder. Isso leva segundos. Para aplicações sensÃveis a latência, configure minReplicas: 1 para sempre ter pelo menos uma réplica pronta, ao custo de billing contÃnuo.
Dapr é opcional mas integrado: o ACA tem integração nativa com Dapr (Distributed Application Runtime) para padrões de microsserviços como pub/sub, service invocation e state management. Você habilita o Dapr por app com uma flag, sem instalação manual.
Environments têm isolamento de rede: cada environment pode ser criado em uma VNet. Apps dentro do mesmo environment se comunicam via DNS interno sem sair para a internet. Apps em environments diferentes precisam de comunicação via URL pública ou via VNet peering.
6. Formas de Implementação​
6.1 Portal do Azure​
Quando usar: criação inicial exploratória, gerenciamento de tráfego entre revisions, visualização de métricas.
Caminho: Create a resource > Containers > Container App
O assistente cria automaticamente um Container Apps Environment se não existir um, ou permite selecionar um existente.
6.2 Azure CLI​
Criar Container Apps Environment:
# Criar Log Analytics workspace (necessário para o environment)
az monitor log-analytics workspace create \
--resource-group rg-containers \
--workspace-name law-aca \
--location brazilsouth
LAW_ID=$(az monitor log-analytics workspace show \
--resource-group rg-containers \
--workspace-name law-aca \
--query customerId -o tsv)
LAW_KEY=$(az monitor log-analytics workspace get-shared-keys \
--resource-group rg-containers \
--workspace-name law-aca \
--query primarySharedKey -o tsv)
# Criar o environment
az containerapp env create \
--name env-producao \
--resource-group rg-containers \
--location brazilsouth \
--logs-workspace-id $LAW_ID \
--logs-workspace-key $LAW_KEY
Criar Container App básica:
az containerapp create \
--name minha-api \
--resource-group rg-containers \
--environment env-producao \
--image minhacr.azurecr.io/api:v1.0 \
--cpu 0.5 \
--memory 1.0Gi \
--min-replicas 1 \
--max-replicas 5 \
--target-port 8080 \
--ingress external \
--registry-server minhacr.azurecr.io \
--registry-identity system \
--env-vars AMBIENTE=producao DB_HOST=meu-banco.postgres.database.azure.com
Atualizar para nova versão da imagem:
az containerapp update \
--name minha-api \
--resource-group rg-containers \
--image minhacr.azurecr.io/api:v2.0 \
--revision-suffix v2-release
Gerenciar tráfego entre revisions (modo Multiple):
# Primeiro, habilitar modo Multiple
az containerapp revision set-mode \
--name minha-api \
--resource-group rg-containers \
--mode multiple
# Listar revisions disponÃveis
az containerapp revision list \
--name minha-api \
--resource-group rg-containers \
--output table
# Dividir tráfego: 90% v1, 10% v2
az containerapp ingress traffic set \
--name minha-api \
--resource-group rg-containers \
--revision-weight \
minha-api--v1-release=90 \
minha-api--v2-release=10
# Após validação: 100% para v2
az containerapp ingress traffic set \
--name minha-api \
--resource-group rg-containers \
--revision-weight minha-api--v2-release=100
Configurar autoscaling baseado em HTTP:
az containerapp update \
--name minha-api \
--resource-group rg-containers \
--min-replicas 0 \
--max-replicas 10 \
--scale-rule-name http-scaler \
--scale-rule-type http \
--scale-rule-http-concurrency 20
Configurar autoscaling baseado em Azure Service Bus:
az containerapp update \
--name processador \
--resource-group rg-containers \
--min-replicas 0 \
--max-replicas 15 \
--scale-rule-name sb-scaler \
--scale-rule-type azure-servicebus \
--scale-rule-metadata \
queueName=fila-processamento \
namespace=meu-servicebus \
messageCount=5 \
--scale-rule-auth \
connectionString=secretRef:sb-connection-string
Usar secrets para credenciais:
# Criar secret
az containerapp secret set \
--name minha-api \
--resource-group rg-containers \
--secrets db-password=MinhasenhaSegura123
# Referenciar o secret como variável de ambiente
az containerapp update \
--name minha-api \
--resource-group rg-containers \
--set-env-vars "DB_PASSWORD=secretref:db-password"
Criar Container App Job (execução única agendada):
az containerapp job create \
--name job-relatorio-diario \
--resource-group rg-containers \
--environment env-producao \
--trigger-type Schedule \
--cron-expression "0 8 * * *" \
--image minhacr.azurecr.io/relatorio:latest \
--cpu 1 \
--memory 2.0Gi
6.3 Bicep​
resource environment 'Microsoft.App/managedEnvironments@2023-05-01' = {
name: 'env-producao'
location: location
properties: {
appLogsConfiguration: {
destination: 'log-analytics'
logAnalyticsConfiguration: {
customerId: logAnalyticsWorkspaceId
sharedKey: logAnalyticsSharedKey
}
}
}
}
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = {
name: 'minha-api'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
managedEnvironmentId: environment.id
configuration: {
ingress: {
external: true
targetPort: 8080
transport: 'http'
}
registries: [
{
server: 'minhacr.azurecr.io'
identity: 'system'
}
]
secrets: [
{
name: 'db-password'
value: dbPassword
}
]
}
template: {
containers: [
{
name: 'api-container'
image: 'minhacr.azurecr.io/api:v1.0'
resources: {
cpu: json('0.5')
memory: '1.0Gi'
}
env: [
{
name: 'AMBIENTE'
value: 'producao'
}
{
name: 'DB_PASSWORD'
secretRef: 'db-password'
}
]
}
]
scale: {
minReplicas: 1
maxReplicas: 10
rules: [
{
name: 'http-scaler'
http: {
metadata: {
concurrentRequests: '20'
}
}
}
]
}
}
}
}
7. Controle e Segurança​
Autenticação no ACR via Managed Identity​
O ACA suporta System-assigned e User-assigned Managed Identities. Para pull de imagens do ACR, use a identidade do sistema:
# Criar app com system-assigned identity
az containerapp create \
--name minha-api \
--registry-server minhacr.azurecr.io \
--registry-identity system \
...
# Atribuir AcrPull à identidade (necessário após criar o app)
APP_IDENTITY=$(az containerapp show \
--name minha-api \
--resource-group rg-containers \
--query identity.principalId -o tsv)
ACR_ID=$(az acr show --name minhacr --query id -o tsv)
az role assignment create \
--assignee $APP_IDENTITY \
--role AcrPull \
--scope $ACR_ID
Autenticação Built-in (Easy Auth)​
O ACA tem integração com o Easy Auth (autenticação sem código): você pode proteger um Container App exigindo que os usuários se autentiquem com Entra ID, GitHub, Google ou outros providers antes de acessar a aplicação, sem nenhuma mudança no código do container.
az containerapp auth microsoft update \
--name minha-api \
--resource-group rg-containers \
--client-id <entra-app-client-id> \
--client-secret <client-secret> \
--issuer https://login.microsoftonline.com/<tenant-id>/v2.0 \
--yes
Network Isolation​
Environments podem ser criados em uma VNet para isolamento de rede. Dois tipos:
| Tipo | Acesso externo | Casos de uso |
|---|---|---|
| External Environment | IP público para ingress externo | Aplicações acessÃveis da internet |
| Internal Environment | Apenas via VNet (sem IP público) | Aplicações internas, comunicação interna entre serviços |
8. Tomada de Decisão​
ACA vs. outros serviços de containers​
| Situação | Melhor escolha | Motivo |
|---|---|---|
| API REST com tráfego variável, scale-to-zero | ACA | Scale-to-zero nativo, billing por uso |
| Microsserviços com comunicação via eventos | ACA com KEDA | Autoscaling baseado em filas/topics |
| Canary deployment ou A/B testing fácil | ACA (Revision traffic) | Divisão de tráfego nativa entre revisions |
| Job batch agendado (cron) | ACA Job ou ACI | ACA Job melhor integrado; ACI mais simples |
| Controle granular de Kubernetes (custom controllers, CRDs) | AKS | ACA não expõe Kubernetes diretamente |
| Aplicação web com slots de staging | App Service | Slots de deployment mais maduros |
| Container simples e rápido sem escala | ACI | Menor overhead, mais simples |
Quando configurar minReplicas: 0 vs. 1?​
| Situação | minReplicas | Motivo |
|---|---|---|
| API com latência crÃtica | 1 | Evita cold start; sempre tem réplica pronta |
| Job/processador com execução eventual | 0 | Zero custo quando inativo |
| Ambiente de desenvolvimento | 0 | Custo mÃnimo, cold start aceitável |
| Produção com SLA de latência | 1 ou mais | Garantia de disponibilidade imediata |
9. Boas Práticas​
Use Revisions para deploys seguros: em vez de atualizar diretamente para 100% do tráfego, habilite o modo Multiple e faça canary deployments: 5% do tráfego para a nova versão, monitore por alguns minutos, expanda para 50%, depois 100%. Se algo der errado, redirecione 100% de volta para a versão anterior imediatamente.
Centralize secrets e nunca coloque em variáveis de ambiente comuns: use secretref para todas as informações sensÃveis. Melhor ainda, use Managed Identity + Key Vault para buscar segredos em runtime, eliminando completamente a necessidade de repassar segredos para o Container App.
Configure health probes para acelerar o autoscaling: defina startupProbe, readinessProbe e livenessProbe para que o ACA saiba exatamente quando uma nova réplica está pronta para receber tráfego durante scale-out e quando uma réplica está com problemas durante operação normal.
Escolha o tamanho de ambiente adequado: environments têm workload profiles. O perfil Consumption é pago por uso e ideal para a maioria dos casos. Perfis Dedicated (D4, D8, D16, etc.) oferecem capacidade reservada para workloads com requisitos de CPU/memória elevados e previsÃveis.
10. Erros Comuns​
Esquecer de atribuir AcrPull após criar o app com system identity
O container app é criado com --registry-identity system, mas o pull de imagem falha. A causa é que a Managed Identity precisa de tempo para ser provisionada e a atribuição de AcrPull precisa ser feita explicitamente após a criação. O app fica em estado de erro com mensagem de imagem não encontrada.
Usar mode Single e perder revisões de rollback
Em modo Single (padrão), quando uma nova revision é criada, a antiga é automaticamente desativada. Se a nova versão tem um bug, não há revision antiga ativa para redirecionar o tráfego imediatamente. Mude para modo Multiple em produção para manter a revision anterior ativa até confirmar que a nova funciona.
Configurar scale-to-zero sem entender o impacto no cold start
Uma API de produção com SLA de 200ms de latência é configurada com minReplicas: 0. Quando não há tráfego por alguns minutos e uma nova requisição chega, o cold start pode levar 5-15 segundos, violando o SLA. Para APIs sensÃveis à latência, use minReplicas: 1.
Confundir revision com deployment
Uma nova revision é criada sempre que a configuração do container muda (imagem, variáveis, CPU/memória). Mudanças em ingress, scaling ou secrets não criam nova revision. Muitos administradores esperam criar uma nova revision ao mudar uma regra de scaling, o que não acontece.
Armazenar state no filesystem do container esperando persistência
O filesystem do container é efêmero em ACA (como em qualquer container). Dados escritos em /tmp ou qualquer diretório local são perdidos quando a réplica é reiniciada ou substituÃda por outra. Use Azure Storage, Azure SQL ou outros serviços externos para estado persistente.
11. Operação e Manutenção​
Verificar Estado e Logs​
# Estado do Container App e revisions
az containerapp show \
--name minha-api \
--resource-group rg-containers \
--query "{Estado:provisioningState, URL:properties.configuration.ingress.fqdn, Replicas:properties.template.scale}" \
--output table
# Logs em tempo real (streaming)
az containerapp logs show \
--name minha-api \
--resource-group rg-containers \
--follow
# Logs de uma revision especÃfica
az containerapp logs show \
--name minha-api \
--resource-group rg-containers \
--revision minha-api--v2-release
# Listar revisions e distribuição de tráfego
az containerapp revision list \
--name minha-api \
--resource-group rg-containers \
--query "[].{Nome:name, Ativa:properties.active, Trafego:properties.trafficWeight, Replicas:properties.replicas}" \
--output table
Monitoramento com Log Analytics​
Com o environment integrado ao Log Analytics, as queries KQL são a principal ferramenta de monitoramento:
// Logs do container
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == "minha-api"
| where TimeGenerated > ago(1h)
| project TimeGenerated, Log_s, RevisionName_s
| order by TimeGenerated desc
// Contagem de requests por revision
ContainerAppSystemLogs_CL
| where Reason_s == "Scaling"
| where TimeGenerated > ago(24h)
| summarize count() by RevisionName_s, bin(TimeGenerated, 5m)
| render timechart
Limites Importantes​
| Item | Limite |
|---|---|
| Container Apps por environment | 20 (padrão, ajustável) |
| Revisions por Container App | 100 (mais antigas são automaticamente limpas) |
| CPU por réplica | 2 vCPU (Consumption profile) |
| Memória por réplica | 4 Gi (Consumption profile) |
| Réplicas por revision | 300 |
| Ingress: tamanho máximo do request | 128 KB (headers) |
12. Integração e Automação​
Padrão Event-Driven com Service Bus​
O caso de uso mais poderoso do ACA é processar mensagens de filas com scaling automático:
GitHub Actions para Deploy ContÃnuo​
# .github/workflows/deploy.yml
name: Deploy to Azure Container Apps
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Build and push to ACR
run: |
az acr build \
--registry minhacr \
--image api:${{ github.sha }} \
.
- name: Deploy to Container Apps
run: |
az containerapp update \
--name minha-api \
--resource-group rg-containers \
--image minhacr.azurecr.io/api:${{ github.sha }} \
--revision-suffix ${{ github.run_number }}
13. Resumo Final​
Pontos essenciais:
- O ACA é um PaaS para containers com gerenciamento automático de Kubernetes, KEDA e Envoy subjacentes. Você não gerencia o cluster.
- A hierarquia é: Environment (cluster compartilhado) > Container App (aplicação) > Revision (versão imutável) > Replica (instância em execução).
- Scale-to-zero é nativo: com
minReplicas: 0, réplicas são removidas quando não há tráfego e criadas automaticamente quando chega demanda. - Revisions permitem canary deployments e A/B testing nativos com divisão percentual de tráfego.
Diferenças crÃticas:
- ACA vs. ACI: ACA tem scaling automático, revisions, traffic splitting e gerenciamento de ciclo de vida; ACI é execução simples sem essas funcionalidades.
- ACA vs. AKS: ACA abstrai completamente o Kubernetes; AKS dá acesso direto ao cluster. ACA é mais simples; AKS é mais flexÃvel e controlável.
- Revision Mode Single vs. Multiple: Single substitui revisions automaticamente (mais simples); Multiple mantém revisions ativas em paralelo (necessário para canary/blue-green).
- minReplicas 0 vs. 1: zero tem cold start mas sem custo em idle; 1 elimina cold start com custo de pelo menos uma réplica sempre ativa.
O que precisa ser lembrado:
- Uma nova revision é criada quando a configuração do container muda (imagem, env vars, recursos), não quando se mudam regras de scaling ou ingress.
- Para pull de imagens do ACR: use
--registry-identity systeme atribuaAcrPullà Managed Identity criada após o deploy. - Environments são regionais e têm VNet associada. Apps dentro do mesmo environment comunicam via DNS interno.
- Para workloads event-driven com Service Bus ou Storage Queue, o ACA com KEDA é a abordagem mais eficiente do ecossistema Azure.
- O comando
az containerapp logs show --followé o equivalente dekubectl logs -fpara acompanhar logs em tempo real.