AKS Multi-Região com Failover no Azure

Neste artigo você vai configurar AKS multi-região com failover no Azure usando estratégia active-passive: um cluster primário em Brazil South recebe todo o tráfego, enquanto um cluster secundário em East US fica em standby pronto para assumir. O Azure Container Registry Premium com geo-replication garante que as imagens estejam disponíveis nas duas regiões sem push duplicado. Ambos os clusters usam Azure CNI com as subnets da Landing Zone Hub-Spoke criadas nos artigos anteriores, Workload Identity para acesso ao Key Vault e o Key Vault Secrets Provider como add-on. Os recursos são criados com Terraform e o projeto inclui uma aplicação demo com pipeline no Azure DevOps para validar o fluxo de build e deploy multi-região.
- 📖 Art. 01: Planejamento de DR Azure e Landing Zone
- 📖 Art. 02: Hub-Spoke Landing Zone com Terraform
- 📖 Art. 03: Azure Firewall e NSGs na Landing Zone
- 📖 Art. 04: Azure Bastion na Landing Zone sem IP Público
- 📖 Art. 05: Azure Front Door e Traffic Manager para Failover
- 📖 Art. 06: DNS Privado Multi-Região no Azure
- 📖 Art. 07: Azure Site Recovery para VMs Multi-Região
- 📖 Art. 08: Azure Storage com Geo-Replicação para DR
- ⚙️ Art. 09 (este): AKS Multi-Região com Failover no Azure
- 🔒 Art. 10: Velero no AKS para Backup e Restore Cross-Region
- 🔒 Art. 11: Runbooks de Failover no Azure Automation
- 🔒 Art. 12: Simular um DR no Azure sem Impacto em Produção
- 🔒 Art. 13: Monitoramento do DR no Azure com Azure Monitor
Sumário
- Estratégia active-passive para AKS
- Arquitetura do lab
- Pré-requisitos
- Passo 1 — Terraform: Azure Container Registry com geo-replication
- Passo 2 — Terraform: AKS Brazil South (cluster primário)
- Passo 3 — Terraform: AKS East US (cluster secundário)
- Passo 4 — Deploy com deploy-infra.sh
- Passo 5 — Validar clusters e ACR
- Passo 6 — Deploy da aplicação demo
- Passo 7 — Simular failover via Front Door
- Troubleshooting
- Limpeza dos recursos
- Próximos passos
Estratégia active-passive para AKS
Existem três estratégias principais para AKS multi-região, com trade-offs entre custo e RTO:
| Estratégia | Cluster secundário | RTO | Custo | Complexidade |
|---|---|---|---|---|
| Active-Active | Recebe tráfego continuamente | < 1 min | $$$$ | Alta — sincronização de estado |
| Active-Passive (warm) | Nodes ligados, zero réplicas | 2–5 min | $$$ | Média |
| Active-Passive (cold) | Apenas node pool system ativo | 5–15 min | $$ | Baixa |
O lab implementa active-passive cold: o cluster de East US tem 2 nodes no system pool (mínimo para o AKS funcionar) e não recebe tráfego em condições normais. Durante o failover, o Front Door redireciona as requisições para o endpoint do cluster de East US após a aplicação ser deployada. O principal benefício é custo — você paga apenas pelos 2 nodes de standby em vez de um cluster completo em produção nas duas regiões.
O Azure Container Registry Premium com geo-replication é essencial nesta estratégia: quando você faz push de uma imagem para o ACR, o Azure replica automaticamente para todas as regiões configuradas. Isso significa que durante o failover, o cluster de East US já tem acesso local à imagem — sem pull cross-region, sem latência adicional e sem depender da disponibilidade da região primária para obter a imagem.
Arquitetura do lab
| Recurso | Nome | Região | Resource Group | Observação |
|---|---|---|---|---|
| Container Registry | acrblogcastilho | Brazil South | rg-blog-castilho-workload-brazilsouth | SKU Premium, geo-replication → East US |
| AKS primário | aks-blog-castilho-brazilsouth | Brazil South | rg-blog-castilho-workload-brazilsouth | 2x Standard_D2s_v3, Azure CNI |
| AKS secundário | aks-blog-castilho-eastus | East US | rg-blog-castilho-workload-eastus | 2x Standard_D2s_v3, standby |
Os dois clusters usam a subnet snet-aks das Spoke VNets criadas no Art. 02. O Azure CNI aloca um IP da subnet para cada pod — ao contrário do kubenet, que usa NAT interno. Com Azure CNI, os pods são alcançáveis diretamente de qualquer ponto da rede hub-spoke: o Bastion do Art. 04 pode acessar pods por IP, o Firewall do Art. 03 pode inspecionar tráfego norte-sul e o DNS privado do Art. 06 resolve serviços internos sem configuração adicional. O Front Door do Art. 05 distribui tráfego entre os dois clusters usando os Services do tipo LoadBalancer como origins.
Pré-requisitos
- Arts. 02–06 deployados — quatro VNets Hub-Spoke, subnets
snet-aksem ambas as Spoke VNets e DNS privado configurado - Art. 05 deployado — Front Door e Traffic Manager existentes para configurar o failover
- Terraform ≥ 1.5 e Azure CLI autenticado (
az login) - Storage Account de remote state configurado (bootstrap da série)
kubectlinstalado localmente para validação pós-deploy
.env local (não versionado) ou o Azure Key Vault para armazenar segredos.Passo 1 — Terraform: Azure Container Registry com geo-replication
O ACR Premium é criado no Resource Group de workload de Brazil South. O bloco georeplications instrui o Azure a manter uma réplica em East US — a sincronização é gerenciada pelo serviço sem configuração adicional de push. O parâmetro admin_enabled = false força autenticação via RBAC (role AcrPull) em vez de credenciais de admin, que é a prática recomendada em produção:
# scripts/art-09-aks-multi-regiao/acr-blog-castilho/main.tf
data "azurerm_resource_group" "this" {
name = "rg-blog-castilho-workload-brazilsouth"
}
resource "azurerm_container_registry" "this" {
name = "acrblogcastilho"
resource_group_name = data.azurerm_resource_group.this.name
location = data.azurerm_resource_group.this.location
sku = "Premium"
admin_enabled = false
tags = var.tags
georeplications {
location = "eastus"
zone_redundancy_enabled = false
tags = var.tags
}
}
Os outputs do módulo expõem o login_server (acrblogcastilho.azurecr.io) e o acr_id, que são usados nos módulos dos clusters AKS para configurar o role assignment AcrPull:
# scripts/art-09-aks-multi-regiao/acr-blog-castilho/outputs.tf
output "login_server" {
value = azurerm_container_registry.this.login_server
}
output "acr_id" {
value = azurerm_container_registry.this.id
}
Passo 2 — Terraform: AKS Brazil South (cluster primário)
O cluster primário usa a subnet snet-aks da Spoke VNet de Brazil South, que pertence ao Resource Group de rede (rg-blog-castilho-network-brazilsouth) — não ao de workload. O Terraform usa data "azurerm_subnet" para referenciar o recurso existente sem precisar de remote state. O identity.type = "SystemAssigned" cria uma Managed Identity para o cluster, e o resource azurerm_role_assignment concede AcrPull ao kubelet_identity — a identidade usada pelos nodes para fazer pull de imagens:
# scripts/art-09-aks-multi-regiao/aks-blog-castilho-brazilsouth/main.tf
data "azurerm_resource_group" "this" {
name = "rg-blog-castilho-workload-brazilsouth"
}
data "azurerm_subnet" "aks" {
name = "snet-aks"
virtual_network_name = "vnet-spoke-blog-castilho-brazilsouth"
resource_group_name = "rg-blog-castilho-network-brazilsouth"
}
data "azurerm_container_registry" "acr" {
name = "acrblogcastilho"
resource_group_name = data.azurerm_resource_group.this.name
}
resource "azurerm_kubernetes_cluster" "this" {
name = "aks-blog-castilho-brazilsouth"
resource_group_name = data.azurerm_resource_group.this.name
location = data.azurerm_resource_group.this.location
dns_prefix = "aks-bcastilho-brs"
kubernetes_version = var.kubernetes_version
tags = var.tags
default_node_pool {
name = "system"
node_count = 2
vm_size = "Standard_D2s_v3"
vnet_subnet_id = data.azurerm_subnet.aks.id
upgrade_settings {
max_surge = "10%"
}
}
identity {
type = "SystemAssigned"
}
network_profile {
network_plugin = "azure"
network_policy = "azure"
}
oidc_issuer_enabled = true
workload_identity_enabled = true
key_vault_secrets_provider {
secret_rotation_enabled = true
}
}
resource "azurerm_role_assignment" "acr_pull" {
scope = data.azurerm_container_registry.acr.id
role_definition_name = "AcrPull"
principal_id = azurerm_kubernetes_cluster.this.kubelet_identity[0].object_id
}
Três configurações merecem destaque. network_plugin = "azure" ativa o Azure CNI: cada pod recebe um IP da subnet snet-aks diretamente, sem overlay. network_policy = "azure" habilita o Azure Network Policy, que implementa as políticas de rede do Kubernetes usando os NSGs da subnet criados no Art. 03. oidc_issuer_enabled = true com workload_identity_enabled = true permite que pods assumam identidades Azure AD sem credenciais estáticas — essencial para acessar o Key Vault no Art. 10.
Passo 3 — Terraform: AKS East US (cluster secundário)
O cluster secundário tem estrutura idêntica ao primário, mas referencia os recursos de East US. A única diferença relevante é que o data "azurerm_container_registry" aponta para o Resource Group de workload de Brazil South — o ACR está registrado lá, embora a réplica esteja em East US. O role assignment AcrPull é criado no escopo do ACR, concedendo acesso à imagem local da réplica:
# scripts/art-09-aks-multi-regiao/aks-blog-castilho-eastus/main.tf
data "azurerm_resource_group" "this" {
name = "rg-blog-castilho-workload-eastus"
}
data "azurerm_subnet" "aks" {
name = "snet-aks"
virtual_network_name = "vnet-spoke-blog-castilho-eastus"
resource_group_name = "rg-blog-castilho-network-eastus"
}
data "azurerm_container_registry" "acr" {
name = "acrblogcastilho"
resource_group_name = "rg-blog-castilho-workload-brazilsouth" # ACR está no RG de BRS
}
resource "azurerm_kubernetes_cluster" "this" {
name = "aks-blog-castilho-eastus"
resource_group_name = data.azurerm_resource_group.this.name
location = data.azurerm_resource_group.this.location
dns_prefix = "aks-bcastilho-eus"
kubernetes_version = var.kubernetes_version
tags = var.tags
default_node_pool {
name = "system"
node_count = 2
vm_size = "Standard_D2s_v3"
vnet_subnet_id = data.azurerm_subnet.aks.id
upgrade_settings {
max_surge = "10%"
}
}
identity {
type = "SystemAssigned"
}
network_profile {
network_plugin = "azure"
network_policy = "azure"
}
oidc_issuer_enabled = true
workload_identity_enabled = true
key_vault_secrets_provider {
secret_rotation_enabled = true
}
}
resource "azurerm_role_assignment" "acr_pull" {
scope = data.azurerm_container_registry.acr.id
role_definition_name = "AcrPull"
principal_id = azurerm_kubernetes_cluster.this.kubelet_identity[0].object_id
}
Passo 4 — Deploy com deploy-infra.sh
O script deploy-infra.sh da série já inclui o art-09 com a ordem correta de dependências: ACR deve existir antes do AKS, pois o Terraform usa data "azurerm_container_registry" para criar o role assignment. Os dois clusters sobem em paralelo após o ACR estar pronto:
# Deploy apenas do art-09 (ACR → AKS BRS + AKS EUS em paralelo)
export AZURE_SUBSCRIPTION_ID=""
cd scripts/
bash deploy-infra.sh art-09
O script gera o backend.hcl automaticamente em cada pasta antes de executar o terraform init, usando o Storage Account de remote state configurado no bootstrap. Os logs ficam em scripts/.deploy-logs/ — um arquivo por recurso. O deploy do ACR leva em torno de 3 minutos; cada cluster AKS leva entre 8 e 15 minutos dependendo da disponibilidade da região.
# Acompanhar o log de um recurso específico em tempo real
tail -f scripts/.deploy-logs/aks-blog-castilho-brazilsouth.log
Passo 5 — Validar clusters e ACR
Após o deploy, obtenha os kubeconfigs dos dois clusters e verifique os nodes:
# Obter kubeconfigs (os nomes viram os contexts do kubectl)
az aks get-credentials \
--resource-group rg-blog-castilho-workload-brazilsouth \
--name aks-blog-castilho-brazilsouth \
--overwrite-existing
az aks get-credentials \
--resource-group rg-blog-castilho-workload-eastus \
--name aks-blog-castilho-eastus \
--overwrite-existing
# Verificar nodes em ambos os clusters
kubectl get nodes -o wide --context aks-blog-castilho-brazilsouth
kubectl get nodes -o wide --context aks-blog-castilho-eastus
O output esperado mostra 2 nodes Ready em cada cluster com IPs da subnet snet-aks (range 10.x.2.0/24). Para confirmar que o ACR está replicado e acessível de East US:
# Verificar status da geo-replication
az acr replication list \
--registry acrblogcastilho \
--query "[].{regiao:location, status:provisioningState, syncStatus:status.syncStatus}" \
-o table
# Saída esperada:
# Regiao Status SyncStatus
# brazilsouth Succeeded Synced
# eastus Succeeded Synced
# Confirmar que o AcrPull está configurado nos dois clusters
az role assignment list \
--scope $(az acr show --name acrblogcastilho --query id -o tsv) \
--role AcrPull \
--query "[].{principal:principalName, type:principalType}" \
-o table
# Obter o OIDC Issuer URL de cada cluster (necessário para Workload Identity)
az aks show \
--resource-group rg-blog-castilho-workload-brazilsouth \
--name aks-blog-castilho-brazilsouth \
--query "oidcIssuerProfile.issuerUrl" -o tsv
az aks show \
--resource-group rg-blog-castilho-workload-eastus \
--name aks-blog-castilho-eastus \
--query "oidcIssuerProfile.issuerUrl" -o tsv
# Exemplo de output:
# https://brazilsouth.oic.prod-aks.azure.com/<TENANT_ID>/<CLUSTER_OIDC_ID>/
# https://eastus.oic.prod-aks.azure.com/<TENANT_ID>/<CLUSTER_OIDC_ID>/
Passo 6 — Deploy da aplicação demo
A aplicação demo é um nginx simples que exibe a região onde está rodando. Duas imagens são geradas — uma por região — usando o mesmo Dockerfile com ARG REGION. O script build-and-push.sh usa az acr build para fazer o build diretamente no ACR, sem necessidade de Docker local. O ACR geo-replication distribui automaticamente para East US após o push:
# Build remoto no ACR e push para as duas tags
az acr login --name acrblogcastilho
az acr build \
--registry acrblogcastilho \
--image dr-demo:brazilsouth \
--build-arg REGION="Brazil South" \
--file app-demo/Dockerfile \
app-demo/
az acr build \
--registry acrblogcastilho \
--image dr-demo:eastus \
--build-arg REGION="East US" \
--file app-demo/Dockerfile \
app-demo/
Com as imagens no ACR, faça o deploy nos dois clusters. Os manifests usam o namespace app-producao e expõem a aplicação via Service do tipo LoadBalancer, que provisiona um Azure Load Balancer público para cada cluster:
# Deploy no cluster primário (Brazil South)
kubectl apply -f app-demo/manifests/namespace.yaml \
--context aks-blog-castilho-brazilsouth
kubectl apply -f app-demo/manifests/deployment-brazilsouth.yaml \
--context aks-blog-castilho-brazilsouth
kubectl apply -f app-demo/manifests/service.yaml \
--context aks-blog-castilho-brazilsouth
kubectl rollout status deployment/dr-demo \
-n app-producao --timeout=120s \
--context aks-blog-castilho-brazilsouth
# Deploy no cluster secundário (East US)
kubectl apply -f app-demo/manifests/namespace.yaml \
--context aks-blog-castilho-eastus
kubectl apply -f app-demo/manifests/deployment-eastus.yaml \
--context aks-blog-castilho-eastus
kubectl apply -f app-demo/manifests/service.yaml \
--context aks-blog-castilho-eastus
kubectl rollout status deployment/dr-demo \
-n app-producao --timeout=120s \
--context aks-blog-castilho-eastus
Para obter os IPs externos dos LoadBalancers (usados como origins no Front Door):
kubectl get svc dr-demo -n app-producao \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}' \
--context aks-blog-castilho-brazilsouth
# Saída: 20.x.x.x (IP do LoadBalancer em Brazil South)
kubectl get svc dr-demo -n app-producao \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}' \
--context aks-blog-castilho-eastus
# Saída: 20.y.y.y (IP do LoadBalancer em East US)
Para automatizar o build e o deploy nos dois clusters em cada push para a branch main, o repositório inclui uma pipeline no Azure DevOps em app-demo/azure-pipelines.yml. A pipeline usa az acr build para o build remoto (sem Docker no agente) e az aks get-credentials com --admin para obter o kubeconfig. Os dois deploys rodam em paralelo após o build concluir — o Service Connection sc-azure-blog-castilho precisa ter o papel AcrPush no ACR e Azure Kubernetes Service Cluster Admin nos dois clusters.
Passo 7 — Simular failover via Front Door
Com os dois clusters rodando e os IPs dos LoadBalancers em mãos, configure os origins no Front Door criado no Art. 05. O objetivo é direcionar 100% do tráfego para Brazil South em condições normais e redirecionar automaticamente para East US quando Brazil South estiver indisponível:
<code">AFD_NAME="afd-blog-castilho" AFD_RG="rg-blog-castilho-network-brazilsouth" ORIGIN_GROUP="og-aks-demo" # Criar origin group com health probe a cada 30s az afd origin-group create \ --resource-group $AFD_RG \ --profile-name $AFD_NAME \ --origin-group-name $ORIGIN_GROUP \ --probe-request-type GET \ --probe-protocol Http \ --probe-interval-in-seconds 30 \ --probe-path "/health.html" \ --sample-size 4 \ --successful-samples-required 3 # Adicionar origin primário (Brazil South) — prioridade 1 az afd origin create \ --resource-group $AFD_RG \ --profile-name $AFD_NAME \ --origin-group-name $ORIGIN_GROUP \ --origin-name aks-brazilsouth \ --host-name "20.x.x.x" \ --http-port 80 \ --priority 1 \ --weight 1000 \ --enabled-state Enabled # Adicionar origin secundário (East US) — prioridade 2 (failover) az afd origin create \ --resource-group $AFD_RG \ --profile-name $AFD_NAME \ --origin-group-name $ORIGIN_GROUP \ --origin-name aks-eastus \ --host-name "20.y.y.y" \ --http-port 80 \ --priority 2 \ --weight 1000 \ --enabled-state Enabled
Para simular o failover sem derrubar o cluster primário, desabilite temporariamente o origin de Brazil South. O Front Door detecta a falha nas health probes e passa a enviar tráfego exclusivamente para East US:
# Simular falha: desabilitar origin primário
az afd origin update \
--resource-group $AFD_RG \
--profile-name $AFD_NAME \
--origin-group-name $ORIGIN_GROUP \
--origin-name aks-brazilsouth \
--enabled-state Disabled
# Aguardar as health probes detectarem a falha (até 90s com probe a cada 30s)
# e verificar que o Front Door passou para East US
curl -s "https://.azurefd.net/" | grep -o "Region: .*"
# Saída esperada: Region: East US
# Restaurar: reabilitar o origin primário
az afd origin update \
--resource-group $AFD_RG \
--profile-name $AFD_NAME \
--origin-group-name $ORIGIN_GROUP \
--origin-name aks-brazilsouth \
--enabled-state Enabled
O tempo de detecção depende da configuração do health probe: com probe-interval-in-seconds 30 e successful-samples-required 3, o Front Door precisa de no mínimo 3 falhas consecutivas antes de remover o origin — o que leva entre 30 e 90 segundos. Para RTO menor, reduza o intervalo para 10 segundos, mas considere que probes mais frequentes geram mais tráfego de saúde nos clusters.
Troubleshooting
| Problema | Causa | Solução |
|---|---|---|
ImagePullBackOff nos pods |
Role AcrPull não propagado ou kubelet identity incorreta |
Verificar o role assignment: az role assignment list --scope $(az acr show --name acrblogcastilho --query id -o tsv) --role AcrPull |
Deploy do Terraform falha com data source not found para a subnet snet-aks |
Subnet não existe no Resource Group de rede — Art. 02 não concluído | Verificar se vnet-spoke-blog-castilho-brazilsouth existe e contém snet-aks antes de prosseguir |
AKS cria nodes mas pods ficam em Pending com 0/2 nodes available |
Subnet sem IPs disponíveis para Azure CNI ou NSG bloqueando | Verificar o range da subnet. Azure CNI reserva IPs por node; com 2 nodes e max 30 pods/node, a subnet precisa de pelo menos 60 IPs livres |
| Health probe do Front Door retorna 502 | NSG da subnet snet-aks bloqueando o range de IPs do Front Door |
Adicionar regra de entrada permitindo tag de serviço AzureFrontDoor.Backend na porta 80 do NSG |
az aks get-credentials retorna erro de permissão |
Usuário sem role Azure Kubernetes Service Cluster User ou Cluster Admin |
Atribuir a role no portal ou via az role assignment create --role "Azure Kubernetes Service Cluster Admin" --assignee <object-id> --scope <aks-id> |
Geo-replication do ACR com status Provisioning por mais de 10 minutos |
Propagação inicial da réplica ainda em andamento — normal para ACRs novos | Aguardar — o pull de imagens da réplica só funciona após o status mudar para Synced |
Limpeza dos recursos
# Destruir AKS East US (não tem dependentes)
cd scripts/art-09-aks-multi-regiao/aks-blog-castilho-eastus
terraform destroy -var subscription_id="$AZURE_SUBSCRIPTION_ID"
# Destruir AKS Brazil South
cd ../aks-blog-castilho-brazilsouth
terraform destroy -var subscription_id="$AZURE_SUBSCRIPTION_ID"
# Destruir ACR por último (os clusters devem ser removidos antes para liberar o role assignment)
cd ../acr-blog-castilho
terraform destroy -var subscription_id="$AZURE_SUBSCRIPTION_ID"
O Terraform destrói o role assignment AcrPull junto com cada cluster, pois o recurso azurerm_role_assignment está no mesmo módulo que o azurerm_kubernetes_cluster. Destruir o ACR antes dos clusters causaria erro porque o Terraform tentaria remoção do role assignment em um escopo que não existe mais.
Próximos passos
Com os dois clusters AKS em produção e o ACR geo-replicado, a camada de containers do lab de DR está operacional. O Art. 10 avança para a proteção dos dados dentro do Kubernetes: Velero instalado nos dois clusters com backend no Azure Blob Storage, schedules automáticos de backup de namespaces e restore cross-region — permitindo recuperar o estado completo de um namespace no cluster secundário após um evento de DR.
- 📖 Art. 01: Planejamento de DR Azure e Landing Zone
- 📖 Art. 02: Hub-Spoke Landing Zone com Terraform
- 📖 Art. 03: Azure Firewall e NSGs na Landing Zone
- 📖 Art. 04: Azure Bastion na Landing Zone sem IP Público
- 📖 Art. 05: Azure Front Door e Traffic Manager para Failover
- 📖 Art. 06: DNS Privado Multi-Região no Azure
- 📖 Art. 07: Azure Site Recovery para VMs Multi-Região
- 📖 Art. 08: Azure Storage com Geo-Replicação para DR
- ⚙️ Art. 09 (este): AKS Multi-Região com Failover no Azure
- 🔒 Art. 10: Velero no AKS para Backup e Restore Cross-Region
- 🔒 Art. 11: Runbooks de Failover no Azure Automation
- 🔒 Art. 12: Simular um DR no Azure sem Impacto em Produção
- 🔒 Art. 13: Monitoramento do DR no Azure com Azure Monitor
Interessado em saber mais sobre artigos relacionados ao Microsoft Azure CLIQUE AQUI
🚀 Vamos nos conectar?
Não perca nenhuma oportunidade! Cadastre-se nas minhas redes e no canal do YouTube para receber conteúdos de TI, Cloud, Azure, Kubernetes e DevOps em primeira mão.
Dica: No Facebook, todos os artigos do blog são publicados automaticamente. Vale a pena curtir!
💬 Dúvidas ou Problemas?
Com o intuito de ajudar a comunidade, caso você tenha dúvidas ou encontre problemas na execução dos comandos deste artigo, deixe um comentário abaixo. Responderei o mais breve possível!
Muito obrigado pela visita e até o próximo post!
Jefferson Castilho Especialista em Cloud & DevOps.Este guia técnico é exclusivo do Blog do Castilho. Explore nossa para mais conteúdos sobre IA e Cloud.


