Fundamentação Teórica: Provision a container by using Azure Container Instances
1. Intuição Inicial​
Imagine que você precisa executar uma tarefa especÃfica: processar um arquivo, enviar um relatório, ou rodar um script de manutenção. Para isso, você normalmente precisaria provisionar uma VM, configurar o sistema operacional, instalar dependências, executar a tarefa e depois desligar a VM. Todo esse processo leva tempo e envolve gerenciamento de infraestrutura que não tem relação com a tarefa em si.
O Azure Container Instances (ACI) elimina esse overhead. Você diz ao Azure: "execute este container com esta imagem, com 1 CPU e 1.5 GB de RAM, por favor". O Azure cuida de toda a infraestrutura subjacente. Em segundos, seu container está rodando. Quando termina, você paga apenas pelo tempo que o container ficou ativo.
É como alugar um quarto de hotel para uma noite, em vez de comprar um apartamento. Sem gerenciamento de propriedade, sem contratos de longo prazo, pague apenas pelo tempo que usou.
2. Contexto​
O ACI ocupa uma posição especÃfica no ecossistema de computação do Azure:
O ACI não é um substituto para o AKS em aplicações de produção complexas, nem para o App Service em aplicações web de longa duração. Ele preenche o nicho de execuções simples, tarefas de curta duração, ambientes de desenvolvimento/teste e processos em batch.
O ACI também tem uma relação especial com o AKS através do Virtual Kubelet: o AKS pode usar o ACI como uma "node virtual" para escalar bursts de carga sem precisar provisionar nodes fÃsicos adicionais.
3. Construção dos Conceitos​
3.1 Container Group: A Unidade Fundamental​
No ACI, a unidade de deploy é o Container Group, não o container individual. Um container group é um conjunto de containers que compartilham o mesmo host, a mesma rede e os mesmos volumes. É o equivalente de um Pod no Kubernetes.
Para casos simples (um único container), você trabalha com um container group de um único container, mas o conceito existe para suportar padrões sidecar onde um container auxiliar complementa o principal.
3.2 Tipos de OS: Linux e Windows​
O ACI suporta containers Linux e Windows. A maioria das cargas de trabalho de container usa Linux. Containers Windows são suportados mas com algumas limitações:
| Aspecto | Linux | Windows |
|---|---|---|
| Tamanhos disponÃveis | Mais opções | Subset menor |
| Custo | Menor | Maior |
| Imagens de base | Alpine, Ubuntu, Debian | Windows Server Core, Nano Server |
| Caso de uso | Maioria das aplicações modernas | Aplicações .NET Framework legacy |
3.3 Tipos de Rede no ACI​
O ACI tem três opções de configuração de rede:
| Tipo | Descrição | Acesso |
|---|---|---|
| Public | IP público atribuÃdo ao container group | AcessÃvel da internet |
| Private (VNet) | Container injetado em uma subnet de VNet | Apenas dentro da VNet e redes conectadas |
| None | Sem interface de rede | Container sem acesso de rede (processamento isolado) |
O modo VNet (Private) é implementado através da delegação de subnet: a subnet deve ter a delegação Microsoft.ContainerInstance/containerGroups configurada para receber containers ACI.
3.4 PolÃtica de Reinicialização​
Define o comportamento quando o processo principal do container termina:
| PolÃtica | Comportamento | Quando usar |
|---|---|---|
| Always | Reinicia sempre que o container para | Serviços de longa duração |
| Never | Não reinicia (termina após completar) | Tarefas batch de execução única |
| OnFailure | Reinicia apenas em caso de falha (exit code != 0) | Tarefas que podem falhar e precisam de retry |
3.5 Recursos: CPU e Memória​
O ACI cobra por vCPU e GB de memória por segundo de execução. Os limites:
- CPU: de 0.1 a 4 vCPU por container (máximo 4 vCPU por container group)
- Memória: de 0.1 a 16 GB por container group (proporcional à CPU)
- GPU: disponÃvel em alguns tamanhos (K80, P100, V100) para workloads de ML
A relação CPU/memória tem restrições: não é possÃvel alocar proporções extremas (muita CPU com pouca memória ou vice-versa).
3.6 Variáveis de Ambiente e Segredos​
Containers recebem configuração via variáveis de ambiente. Para informações sensÃveis (senhas, chaves de API), o ACI suporta secure environment variables: o valor é enviado de forma segura e não aparece nos logs ou na saÃda da CLI/portal.
# Variável comum (visÃvel nos logs)
--environment-variables AMBIENTE=producao
# Variável segura (valor não aparece em logs)
--secure-environment-variables DB_PASSWORD=minhasenha
3.7 Volumes e Persistência​
Por padrão, o storage de um container ACI é efêmero: dados escritos dentro do container são perdidos quando ele para. Para persistência, o ACI suporta:
| Tipo de volume | Protocolo | Quando usar |
|---|---|---|
| Azure Files | SMB | Compartilhamento entre containers e persistência |
| Azure Files (gitRepo - deprecated) | - | Clone de repositório Git |
| emptyDir | - | Compartilhamento temporário entre containers do mesmo group |
| Secret | - | Montar segredos como arquivos |
O volume Azure Files é montado como um compartilhamento SMB dentro do container, permitindo que os dados persistam além do ciclo de vida do container.
4. Visão Estrutural​
5. Funcionamento na Prática​
Ciclo de Vida de um Container ACI​
Comportamentos Importantes e Não Óbvios​
Pull de imagem acontece em cada criação: o ACI não mantém um cache de imagens entre execuções. Cada vez que um container group é criado, a imagem é baixada novamente do registry. Para imagens grandes (centenas de MB), isso adiciona tempo de inicialização. Para otimizar, use imagens menores (Alpine) e layers bem organizadas.
Containers parados ainda incorrem em custo de armazenamento: quando um container group está no estado Stopped, não há cobrança por CPU e memória, mas o container group ainda existe como um recurso. Para eliminar completamente o custo, exclua o container group.
Managed Identity funciona no ACI: é possÃvel atribuir uma Managed Identity a um container group. Isso permite que o código dentro do container obtenha tokens do Entra ID para acessar outros serviços Azure (Key Vault, Storage, etc.) sem credenciais hardcoded.
O FQDN gerado é imprevisÃvel: ao criar um container com IP público, o Azure gera automaticamente um FQDN no formato <dns-name-label>.<region>.azurecontainer.io. Esse label deve ser único na região. Se você não especificar um label DNS, o container só é acessÃvel pelo IP.
6. Formas de Implementação​
6.1 Portal do Azure​
Quando usar: criação exploratória, testes rápidos, verificação de estado.
Caminho: Create a resource > Containers > Container Instances
O assistente tem as abas:
- Basics: imagem, nome, SKU (Linux/Windows), região
- Networking: tipo de rede, portas, DNS label
- Advanced: variáveis de ambiente, restart policy, comandos personalizados, volumes
- Tags
6.2 Azure CLI​
Criar container simples com IP público:
az container create \
--name meu-container \
--resource-group rg-containers \
--image nginx:alpine \
--cpu 0.5 \
--memory 0.5 \
--ip-address Public \
--ports 80 \
--dns-name-label meu-nginx-unico \
--restart-policy Always \
--location brazilsouth
Criar container usando imagem do ACR com Managed Identity:
# Criar identidade gerenciada
az identity create \
--name id-aci-producao \
--resource-group rg-containers
# Atribuir AcrPull ao ACR para a identidade
ACR_ID=$(az acr show --name minhacr --resource-group rg-containers --query id -o tsv)
IDENTITY_ID=$(az identity show --name id-aci-producao --resource-group rg-containers --query principalId -o tsv)
az role assignment create --assignee $IDENTITY_ID --role AcrPull --scope $ACR_ID
# Criar container usando a identidade para pull
az container create \
--name api-container \
--resource-group rg-containers \
--image minhacr.azurecr.io/api-gateway:v1.2.3 \
--cpu 1 \
--memory 1.5 \
--ip-address Private \
--vnet vnet-producao \
--subnet subnet-containers \
--assign-identity $(az identity show --name id-aci-producao --resource-group rg-containers --query id -o tsv) \
--registry-login-server minhacr.azurecr.io \
--restart-policy OnFailure
Criar container com variáveis de ambiente e volume Azure Files:
# Criar compartilhamento Azure Files
STORAGE_KEY=$(az storage account keys list \
--account-name minhaconta \
--resource-group rg-containers \
--query "[0].value" -o tsv)
az storage share create \
--name dados-container \
--account-name minhaconta \
--account-key $STORAGE_KEY
# Criar container com volume montado
az container create \
--name processador \
--resource-group rg-containers \
--image minhacr.azurecr.io/processador:latest \
--cpu 2 \
--memory 4 \
--ip-address None \
--restart-policy Never \
--environment-variables AMBIENTE=producao BUCKET=resultados \
--secure-environment-variables DB_PASSWORD=minhasenha \
--azure-file-volume-account-name minhaconta \
--azure-file-volume-account-key $STORAGE_KEY \
--azure-file-volume-share-name dados-container \
--azure-file-volume-mount-path /mnt/dados
Verificar estado e logs:
# Estado do container
az container show \
--name meu-container \
--resource-group rg-containers \
--query "{Estado:instanceView.state, IP:ipAddress.ip, FQDN:ipAddress.fqdn}" \
--output table
# Logs do container (stdout/stderr)
az container logs \
--name meu-container \
--resource-group rg-containers \
--follow # streaming em tempo real
# Acessar shell interativo no container (se ainda estiver rodando)
az container exec \
--name meu-container \
--resource-group rg-containers \
--exec-command "/bin/sh"
# Parar e iniciar
az container stop --name meu-container --resource-group rg-containers
az container start --name meu-container --resource-group rg-containers
# Excluir
az container delete --name meu-container --resource-group rg-containers --yes
Deploy via arquivo YAML (container groups complexos):
# container-group.yaml
apiVersion: 2021-10-01
location: brazilsouth
name: meu-container-group
properties:
containers:
- name: app-principal
properties:
image: minhacr.azurecr.io/api:v1.0
resources:
requests:
cpu: 1
memoryInGb: 1.5
ports:
- port: 80
protocol: TCP
environmentVariables:
- name: AMBIENTE
value: producao
- name: DB_PASSWORD
secureValue: minhasenha
volumeMounts:
- name: dados
mountPath: /mnt/dados
- name: log-sidecar
properties:
image: fluent/fluent-bit:latest
resources:
requests:
cpu: 0.5
memoryInGb: 0.5
volumeMounts:
- name: dados
mountPath: /mnt/logs
osType: Linux
ipAddress:
type: Public
ports:
- port: 80
protocol: TCP
dnsNameLabel: meu-app-prod
restartPolicy: Always
volumes:
- name: dados
azureFile:
shareName: dados-container
storageAccountName: minhaconta
storageAccountKey: <key>
type: Microsoft.ContainerInstance/containerGroups
# Deploy via arquivo YAML
az container create \
--resource-group rg-containers \
--file container-group.yaml
6.3 PowerShell​
# Criar container simples
$container = New-AzContainerInstanceObject `
-Name "app-container" `
-Image "nginx:alpine" `
-RequestCpu 0.5 `
-RequestMemoryInGb 0.5 `
-Port @(New-AzContainerInstancePortObject -Port 80 -Protocol TCP)
New-AzContainerGroup `
-ResourceGroupName "rg-containers" `
-Name "meu-container-group" `
-Location "brazilsouth" `
-Container @($container) `
-OsType Linux `
-IpAddressType Public `
-DnsNameLabel "meu-nginx-ps" `
-RestartPolicy Always
6.4 Bicep​
resource containerGroup 'Microsoft.ContainerInstance/containerGroups@2023-05-01' = {
name: 'meu-container-group'
location: location
properties: {
containers: [
{
name: 'app-container'
properties: {
image: 'minhacr.azurecr.io/api:v1.0'
resources: {
requests: {
cpu: 1
memoryInGB: 1.5
}
}
ports: [
{
port: 80
protocol: 'TCP'
}
]
environmentVariables: [
{
name: 'AMBIENTE'
value: 'producao'
}
{
name: 'DB_PASSWORD'
secureValue: dbPassword // parametro seguro
}
]
}
}
]
osType: 'Linux'
ipAddress: {
type: 'Public'
ports: [
{
port: 80
protocol: 'TCP'
}
]
dnsNameLabel: 'meu-app-prod-${uniqueString(resourceGroup().id)}'
}
restartPolicy: 'Always'
}
}
7. Controle e Segurança​
Autenticação em Registries Privados​
Para usar imagens do ACR, o ACI pode autenticar de três formas:
- Managed Identity (recomendado): o container group tem uma identidade com papel AcrPull no ACR
- Service Principal: username = service principal ID, senha = client secret
- Admin credentials: username = nome do registry, senha = admin password (não recomendado)
# Usando Managed Identity (necessário especificar o registry login server)
az container create \
--assign-identity <identity-resource-id> \
--registry-login-server minhacr.azurecr.io \
...
Containers em VNet: Isolamento de Rede​
Para workloads que precisam acessar recursos internos da VNet (bancos de dados, serviços privados), o ACI em modo VNet é essencial:
# Criar subnet com delegação para ACI
az network vnet subnet create \
--name subnet-aci \
--vnet-name vnet-producao \
--resource-group rg-networking \
--address-prefix 10.0.5.0/24 \
--delegations Microsoft.ContainerInstance/containerGroups
# Container na VNet
az container create \
--ip-address Private \
--vnet vnet-producao \
--subnet subnet-aci \
...
Restrição importante: containers em VNet não podem ter IP público simultâneo. A escolha é uma ou outra.
Iniciativas de Segurança​
- Nunca use variáveis de ambiente comuns para senhas; use sempre
--secure-environment-variables - Para segredos mais complexos, use Managed Identity + Key Vault para buscar os segredos em runtime
- Containers em produção devem estar em VNet, não com IP público direto
- Imagens devem vir de registries privados (ACR), não diretamente do Docker Hub em produção
8. Tomada de Decisão​
ACI vs. outros serviços de compute​
| Situação | Melhor escolha | Motivo |
|---|---|---|
| Tarefa batch de curta duração | ACI com restartPolicy: Never | Paga apenas pelo tempo de execução |
| API REST simples de longa duração | App Service Containers | Mais features web (SSL, custom domain, deployment slots) |
| Microserviços em produção, múltiplas instâncias | AKS | Orquestração, scaling automático, service mesh |
| Ambiente de dev/test de container | ACI | Rápido, sem overhead de cluster |
| Processamento de eventos (Function-like) | Azure Container Apps | Scaling to zero nativo, KEDA |
| Container que precisa acessar recursos VNet | ACI em modo VNet | Integração nativa com VNet |
| Burst de carga em AKS | ACI via Virtual Kubelet | Scale out rápido sem novos nodes |
Quando usar restart policy diferente?​
| Cenário | Restart Policy | Motivo |
|---|---|---|
| Web server, API | Always | Reinicia se travar ou falhar |
| Job de processamento de dados | Never | Executa uma vez e termina |
| Script que pode ter falha transitória | OnFailure | Retry em falha, não reinicia após sucesso |
9. Boas Práticas​
Use imagens mÃnimas (Alpine, Distroless): imagens menores iniciam mais rápido (menos dados para baixar), custam menos em armazenamento no ACR e têm menor superfÃcie de ataque de segurança.
Prefira Managed Identity a credenciais explÃcitas: em vez de passar senhas e chaves de API como variáveis de ambiente, configure uma Managed Identity no container group e use-a para acessar Key Vault, Storage e outros serviços Azure.
Para tarefas batch, use restartPolicy: Never e verifique o exit code: um script que termina com exit code 0 indica sucesso. Exit code diferente de zero indica falha. Use essa convenção para que o ACI saiba se a tarefa foi bem-sucedida.
Defina limites de CPU e memória conservadores: o ACI cobra por recurso alocado, não por uso. Se você aloca 4 vCPU mas usa 0.5, paga por 4. Dimensione com base em benchmarks reais da aplicação.
Nomeie DNS labels de forma previsÃvel e única: o DNS label é parte do FQDN público. Use um padrão como <app>-<ambiente>-<sufixo-unico> para evitar conflitos e facilitar identificação.
10. Erros Comuns​
Usar restart policy "Always" para tarefas batch
Um script de processamento termina com exit code 0 (sucesso). Com Always, o ACI reinicia imediatamente. O script processa os mesmos dados de novo e de novo, em loop, consumindo recursos e potencialmente processando dados duplicados. Para tarefas batch, use Never.
Não especificar DNS label e depois não conseguir o FQDN
O container é criado com IP público mas sem --dns-name-label. O IP muda a cada recriação do container group. O time de infra precisa atualizar manualmente todos os sistemas que apontam para o IP. Sempre defina um DNS label previsÃvel para containers com IP público.
Pull de imagem falha silenciosamente por falta de permissão no ACR
O container group é criado, mas fica no estado Pending indefinidamente. O erro "image pull failed" está nos logs mas não é óbvio no portal. A causa é que o container não tem credenciais para acessar o ACR privado. Configure a Managed Identity com AcrPull antes de criar o container.
Container em VNet não consegue acessar internet para APIs externas
Um container na VNet precisa chamar uma API externa. O tráfego de saÃda da subnet não tem route para a internet (sem NAT Gateway, sem UDR para internet). O container fica travado aguardando resposta. Containers em VNet que precisam de acesso à internet requerem configuração explÃcita de saÃda (NAT Gateway ou Azure Firewall com UDR).
Armazenar dados no filesystem do container sem montar volume
Um job de processamento grava resultados em /tmp/resultados. O job termina. O container group é excluÃdo. Os resultados se perdem. Para persistência, monte sempre um volume Azure Files para os diretórios onde dados importantes são escritos.
11. Operação e Manutenção​
Monitoramento​
O ACI envia métricas para o Azure Monitor:
| Métrica | O que mede |
|---|---|
| CpuUsage | vCPU usadas pelo container group |
| MemoryUsage | Memória em bytes em uso |
| NetworkBytesReceivedPerSecond | Tráfego de entrada |
| NetworkBytesTransmittedPerSecond | Tráfego de saÃda |
Para acessar os logs de uma container em execução ou após término:
# Logs do container principal
az container logs --name meu-container --resource-group rg-containers
# Logs de um container especÃfico em um group com múltiplos containers
az container logs \
--name meu-container-group \
--resource-group rg-containers \
--container-name sidecar-container
Os logs são retidos enquanto o container group existe. Após excluir o container group, os logs são perdidos a menos que tenham sido enviados para um serviço de log (Log Analytics, Azure Monitor).
Configurar Log Analytics​
WORKSPACE_ID=$(az monitor log-analytics workspace show \
--workspace-name law-monitoring \
--resource-group rg-monitoring \
--query customerId -o tsv)
WORKSPACE_KEY=$(az monitor log-analytics workspace get-shared-keys \
--workspace-name law-monitoring \
--resource-group rg-monitoring \
--query primarySharedKey -o tsv)
az container create \
--name meu-container \
--resource-group rg-containers \
--log-analytics-workspace $WORKSPACE_ID \
--log-analytics-workspace-key $WORKSPACE_KEY \
...
Com Log Analytics configurado, os logs do container são enviados automaticamente para o workspace e podem ser consultados com KQL mesmo após o container ser excluÃdo.
Limites Importantes​
| Item | Limite |
|---|---|
| CPUs por container group | 4 vCPU |
| Memória por container group | 16 GB |
| Containers por container group | 60 |
| Container groups por assinatura por região | 100 (padrão, ajustável) |
| Duração máxima de um container group | Sem limite técnico (mas limitações de billing) |
| Portas por container group | Múltiplas, mas sem sobreposição entre containers |
12. Integração e Automação​
ACI como Backend para Azure Logic Apps e Functions​
O ACI pode ser criado e destruÃdo programaticamente via API REST, tornando-o ideal para orquestração de jobs:
Virtual Kubelet: ACI como Node do AKS​
O AKS pode usar o ACI como um "node virtual" para absorver bursts de demanda sem escalar nodes reais do cluster:
# Habilitar o addon Virtual Nodes no AKS
az aks enable-addons \
--resource-group rg-aks \
--name meu-cluster \
--addons virtual-node \
--subnet-name subnet-aci
Com isso, Pods com o toleration virtual-kubelet.io/provider=azure são agendados no ACI em vez de em nodes fÃsicos, permitindo escala instantânea sem tempo de provisioning de node.
Automação via ARM/Bicep em Pipelines​
Para pipelines de processamento de dados onde cada run é um container:
#!/bin/bash
# Pipeline: criar container, aguardar conclusão, coletar resultado, excluir
CONTAINER_NAME="job-$(date +%Y%m%d%H%M%S)"
RG="rg-containers"
# Criar container
az container create \
--name $CONTAINER_NAME \
--resource-group $RG \
--image minhacr.azurecr.io/processador:latest \
--cpu 2 --memory 4 \
--ip-address None \
--restart-policy Never \
--environment-variables INPUT_FILE="arquivo-$(date +%Y%m%d).csv"
# Aguardar conclusão
az container wait \
--name $CONTAINER_NAME \
--resource-group $RG \
--condition terminated
# Verificar exit code
EXIT_CODE=$(az container show \
--name $CONTAINER_NAME \
--resource-group $RG \
--query "containers[0].instanceView.currentState.exitCode" -o tsv)
if [ "$EXIT_CODE" == "0" ]; then
echo "Job concluido com sucesso"
else
echo "Job falhou com exit code $EXIT_CODE"
az container logs --name $CONTAINER_NAME --resource-group $RG
fi
# Limpar container
az container delete --name $CONTAINER_NAME --resource-group $RG --yes
13. Resumo Final​
Pontos essenciais:
- O ACI executa containers sem gerenciamento de VM ou cluster. É ideal para tarefas de curta duração, batch jobs e desenvolvimento.
- A unidade de deploy é o Container Group, que pode conter múltiplos containers compartilhando rede e volumes.
- Três polÃticas de reinicialização: Always (serviços), Never (tarefas batch), OnFailure (retry em falha).
- Três modos de rede: Public (IP público), Private/VNet (isolamento de rede), None (sem rede).
Diferenças crÃticas:
- ACI vs. AKS: ACI é para containers simples, execuções únicas ou desenvolvimento. AKS é para microsserviços em produção, múltiplas réplicas e orquestração complexa.
- Restart policy Never vs. Always: Never é para jobs que executam uma vez; Always é para serviços contÃnuos. Usar Always em um job batch cria um loop infinito.
- Storage efêmero vs. Volume Azure Files: dados no filesystem do container são perdidos quando o container para. Dados em volume Azure Files persistem.
- IP público vs. VNet mode: containers em VNet não podem ter IP público; escolha um ou outro.
O que precisa ser lembrado:
- O ACI cobra por vCPU e GB de memória alocados, por segundo de execução.
- Containers parados (
Stopped) não cobram por CPU/memória, mas o container group ainda existe (pode incorrer em custos de armazenamento associado). - Para imagens privadas do ACR, use Managed Identity com papel
AcrPull. - A subnet para ACI em VNet precisa ter a delegação
Microsoft.ContainerInstance/containerGroups. - O comando
az container wait --condition terminatedbloqueia até que o container termine, útil em pipelines automatizados. - Logs são perdidos quando o container group é excluÃdo. Configure Log Analytics para retenção.