Pular para o conteúdo principal

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.

100%
Scroll para zoom · Arraste para mover · 📱 Pinch para zoom no celular

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​

100%
Scroll para zoom · Arraste para mover · 📱 Pinch para zoom no celular

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:

ModoComportamentoUso
Single (padrão)Apenas uma revision ativa por vez. Nova revision substitui a antiga automaticamente.Aplicações simples sem necessidade de A/B testing
MultipleMú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:

TipoDescriçãoURL gerada
External (enabled)Acessível da internet via HTTPShttps://minha-api.<hash>.brazilsouth.azurecontainerapps.io
Internal (enabled)Acessível apenas dentro do environmenthttps://minha-api (nome curto)
DisabledSem 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 scalerO que monitoraExemplo
HTTPRequisições HTTP simultâneasEscalar quando > 10 req concorrentes por réplica
CPUUso de CPUEscalar quando CPU > 70%
MemoryUso de memóriaEscalar quando memória > 80%
Azure Service BusMensagens na fila1 réplica por mensagem na fila
Azure Storage QueueMensagens na fila1 réplica a cada 5 mensagens
CustomQualquer métrica via KEDAQualquer 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.

TipoDuraçãoTriggerBilling
Container AppContínuaTráfego / mensagensPor vCPU/s e GB/s usados
Container App JobFinita (termina)Manual, Scheduled (cron), Event-drivenPor execução

4. Visão Estrutural​

100%
Scroll para zoom · Arraste para mover · 📱 Pinch para zoom no celular

5. Funcionamento na Prática​

Ciclo de Vida de um Deploy​

100%
Scroll para zoom · Arraste para mover · 📱 Pinch para zoom no celular

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:

TipoAcesso externoCasos de uso
External EnvironmentIP público para ingress externoAplicações acessíveis da internet
Internal EnvironmentApenas 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çãoMelhor escolhaMotivo
API REST com tráfego variável, scale-to-zeroACAScale-to-zero nativo, billing por uso
Microsserviços com comunicação via eventosACA com KEDAAutoscaling baseado em filas/topics
Canary deployment ou A/B testing fácilACA (Revision traffic)Divisão de tráfego nativa entre revisions
Job batch agendado (cron)ACA Job ou ACIACA Job melhor integrado; ACI mais simples
Controle granular de Kubernetes (custom controllers, CRDs)AKSACA não expõe Kubernetes diretamente
Aplicação web com slots de stagingApp ServiceSlots de deployment mais maduros
Container simples e rápido sem escalaACIMenor overhead, mais simples

Quando configurar minReplicas: 0 vs. 1?​

SituaçãominReplicasMotivo
API com latência crítica1Evita cold start; sempre tem réplica pronta
Job/processador com execução eventual0Zero custo quando inativo
Ambiente de desenvolvimento0Custo mínimo, cold start aceitável
Produção com SLA de latência1 ou maisGarantia 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​

ItemLimite
Container Apps por environment20 (padrão, ajustável)
Revisions por Container App100 (mais antigas são automaticamente limpas)
CPU por réplica2 vCPU (Consumption profile)
Memória por réplica4 Gi (Consumption profile)
Réplicas por revision300
Ingress: tamanho máximo do request128 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:

100%
Scroll para zoom · Arraste para mover · 📱 Pinch para zoom no celular

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 system e atribua AcrPull à 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 de kubectl logs -f para acompanhar logs em tempo real.