Azure Resource Groups: Fundação da Organização em Nuvem
Um Resource Group (Grupo de Recursos) no Azure é um container lógico que agrupa todos os recursos necessários para uma solução. Diferentemente de outras plataformas de nuvem que distribuem recursos por regiões ou projetos sem uma organização clara, o Azure força uma abordagem estruturada e explícita. Você não pode criar um recurso sem designá-lo a um grupo específico; isso garante rastreabilidade, controle de acesso e faturamento consolidado.
A importância de uma estratégia bem definida de Resource Groups vai além da organização visual. Quando você implanta um grupo inteiro, pode destruir todos os seus recursos de uma vez, o que é essencial para ambientes de teste e desenvolvimento. Além disso, você pode aplicar políticas (Azure Policy), controle de acesso baseado em função (RBAC) e tags a todos os recursos dentro de um grupo, economizando configurações repetitivas e reduzindo erros humanos.
Criando e Gerenciando Resource Groups
A forma mais direta de criar um Resource Group é pela CLI do Azure. Vou mostrar um exemplo prático e funcional:
# Instalar Azure CLI (se ainda não tiver)
# No macOS: brew install azure-cli
# No Windows: choco install azure-cli
# No Linux: curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
# Login no Azure
az login
# Criar um Resource Group
az group create \
--name rg-produção-aks \
--location eastus
# Listar todos os grupos de recursos
az group list --output table
# Deletar um Resource Group (cuidado: deleta tudo dentro dele)
az group delete --name rg-produção-aks --yes
A flag --location é crítica: ela define a região onde os recursos serão hospedados. Escolha regiões próximas aos seus usuários finais para reduzir latência. A nomeação também importa: use prefixos que indiquem propósito (rg-), ambiente (produção, dev) e contexto (aks, database), tornando gerenciamento futuro mais fácil.
Aplicando Tags e Políticas
Tags são metadados que você aplica a recursos para rastreamento de custos, propriedade e ciclo de vida. Quando você tiver centenas de recursos, tags corretas são a diferença entre saber exatamente o que você está pagando e ter uma fatura misteriosa no final do mês.
# Adicionar tags a um Resource Group existente
az group update \
--name rg-produção-aks \
--tags ambiente=produção proprietario=devops custo-centro=eng-001
# Consultar grupos por tag
az group list --query "[?tags.ambiente=='produção']" --output table
# Criar um grupo com tags já incluídas (mais eficiente)
az group create \
--name rg-dev-aks \
--location eastus \
--tags ambiente=desenvolvimento proprietario=devops
Azure Kubernetes Service (AKS): Orquestração de Contêineres Simplificada
Azure Kubernetes Service é a oferta gerenciada do Azure para Kubernetes. Diferentemente de gerenciar um cluster Kubernetes do zero, o AKS abstrai a complexidade da camada de controle (control plane), permitindo que você foque em aplicações, não em infraestrutura. A Microsoft gerencia atualizações, patches de segurança e alta disponibilidade do control plane automaticamente.
Um cluster AKS reside dentro de um Resource Group e depende de uma rede virtual (VNet), mas para começar você não precisa se preocupar com essas complexidades—o AKS cria muitos desses recursos automaticamente. O que você realmente controla são os node pools (grupos de nós onde seus contêineres executam), versão do Kubernetes, scaling e acesso à rede.
Criando um Cluster AKS
# Pré-requisito: ter um Resource Group criado (feito na seção anterior)
# Criar um cluster AKS básico
az aks create \
--resource-group rg-produção-aks \
--name cluster-produção \
--node-count 3 \
--vm-set-type VirtualMachineScaleSets \
--load-balancer-sku standard \
--enable-managed-identity \
--network-plugin azure \
--docker-bridge-address 172.17.0.1/16 \
--service-cidr 10.0.0.0/16 \
--dns-service-ip 10.0.0.10 \
--generate-ssh-keys \
--tier free
# Este comando leva cerca de 5-10 minutos. Enquanto isso, entenda os parâmetros:
# --node-count: quantidade inicial de nós
# --vm-set-type VirtualMachineScaleSets: permite scaling automático (recomendado)
# --enable-managed-identity: segurança—deixe o Azure gerenciar credenciais
# --network-plugin azure: usa CNI do Azure (mais flexível que kubenet)
Após a criação, você precisa configurar suas credenciais locais para interagir com o cluster:
# Obter credenciais do cluster
az aks get-credentials \
--resource-group rg-produção-aks \
--name cluster-produção \
--overwrite-existing
# Verificar que kubectl está apontando para o cluster correto
kubectl cluster-info
kubectl get nodes
O output do kubectl get nodes mostrará algo assim:
NAME STATUS ROLES AGE VERSION
aks-nodepool1-12345678-vmss000000 Ready agent 2m34s v1.27.3
aks-nodepool1-12345678-vmss000001 Ready agent 2m28s v1.27.3
aks-nodepool1-12345678-vmss000002 Ready agent 2m22s v1.27.3
Escalabilidade e Node Pools
Um dos maiores benefícios do AKS é a capacidade de ter múltiplos node pools com diferentes configurações. Imagine que você tem aplicações web que precisam de CPU e aplicações de processamento que precisam de GPU. Em vez de um cluster homogêneo, você cria pools diferentes:
# Criar um node pool adicional com máquinas mais poderosas
az aks nodepool add \
--resource-group rg-produção-aks \
--cluster-name cluster-produção \
--name gpupool \
--node-count 2 \
--vm-set-type VirtualMachineScaleSets \
--node-vm-size Standard_NC6 \
--labels workload=gpu \
--taints gpu=true:NoSchedule
# Listar todos os node pools
az aks nodepool list \
--resource-group rg-produção-aks \
--cluster-name cluster-produção \
--output table
# Configurar auto-scaling para um pool
az aks nodepool update \
--resource-group rg-produção-aks \
--cluster-name cluster-produção \
--name nodepool1 \
--enable-cluster-autoscaler \
--min-count 2 \
--max-count 10
A taint gpu=true:NoSchedule garante que apenas pods que tolerem essa taint sejam agendados nesse pool. Em seu YAML de deployment, você declararia:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ml-training-job
spec:
replicas: 1
selector:
matchLabels:
app: ml-training
template:
metadata:
labels:
app: ml-training
spec:
nodeSelector:
workload: gpu
tolerations:
- key: gpu
operator: Equal
value: "true"
effect: NoSchedule
containers:
- name: training
image: seu-registro.azurecr.io/ml-training:latest
resources:
limits:
nvidia.com/gpu: 1
Azure Pipelines: Automação de Build, Teste e Deploy
Azure Pipelines é o serviço de CI/CD (Integração Contínua / Entrega Contínua) do Azure. Ele automatiza o processo de pegar código do repositório, compilar, testar e fazer deploy para produção—ou qualquer outro ambiente. Sem pipelines, um desenvolvedor teria que fazer esses passos manualmente toda vez, o que é lento, propenso a erros e não escala com times crescentes.
A beleza do Azure Pipelines é que ele integra perfeitamente com o Azure DevOps, GitHub, GitLab e Bitbucket. Você define seus passos em um arquivo YAML (chamado azure-pipelines.yml) no repositório, e o sistema executa automaticamente quando você faz push de código. Você também pode usar a interface visual, mas YAML é mais versionado e colaborativo.
Estrutura de um Pipeline Básico
# azure-pipelines.yml
# Este arquivo deve estar na raiz do seu repositório
trigger:
- main # Executa quando houver push na branch main
pool:
vmImage: 'ubuntu-latest' # Ambiente onde o pipeline executa
variables:
dockerRegistryServiceConnection: 'seu-registro-acr'
imageRepository: 'seu-app'
containerRegistry: 'seuregistry.azurecr.io'
dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
tag: '$(Build.BuildId)'
stages:
- stage: Build
displayName: Build e Push da Imagem Docker
jobs:
- job: BuildImage
displayName: Build Image
steps:
- task: Docker@2
displayName: Build e Push Imagem
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
latest
- stage: Deploy
displayName: Deploy para AKS
dependsOn: Build
condition: succeeded()
jobs:
- deployment: DeployToAKS
displayName: Deploy para Produção
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- task: KubernetesManifest@0
displayName: Deploy
inputs:
action: 'deploy'
kubernetesServiceConnection: 'cluster-produção'
namespace: 'default'
manifests: |
$(Pipeline.Workspace)/manifests/deployment.yml
$(Pipeline.Workspace)/manifests/service.yml
Este pipeline tem dois estágios: primeiro faz build da imagem Docker e envia para um registro de container (Azure Container Registry), depois realiza o deploy dessa imagem no AKS. O dependsOn: Build garante que o Deploy só aconteça se o Build tiver sucesso.
Conectando Azure Pipelines ao Azure Container Registry (ACR)
Você precisa de um registro privado para armazenar suas imagens Docker. Azure Container Registry é gerenciado, integrado e seguro:
# Criar um registro de container
az acr create \
--resource-group rg-produção-aks \
--name seuregistry \
--sku Basic \
--admin-enabled false
# Autenticar o AKS para puxar imagens do ACR
az aks update \
--resource-group rg-produção-aks \
--name cluster-produção \
--attach-acr seuregistry
# Listar imagens no registro
az acr repository list --name seuregistry --output table
A integração com az aks update --attach-acr é essencial: ela cria uma identidade gerenciada que permite que o AKS puxe imagens sem você precisar de senhas ou tokens.
Estrutura Recomendada de Manifests Kubernetes
Seus manifests (arquivos YAML) devem estar em um diretório chamado manifests no repositório:
# manifests/deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: minha-aplicacao
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: minha-aplicacao
template:
metadata:
labels:
app: minha-aplicacao
spec:
containers:
- name: app
image: seuregistry.azurecr.io/seu-app:latest
ports:
- containerPort: 8080
env:
- name: ENVIRONMENT
value: "production"
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
imagePullSecrets:
- name: acr-secret
# manifests/service.yml
apiVersion: v1
kind: Service
metadata:
name: minha-aplicacao-service
namespace: default
spec:
type: LoadBalancer
selector:
app: minha-aplicacao
ports:
- protocol: TCP
port: 80
targetPort: 8080
Variáveis e Secrets no Pipeline
Nunca coloque senhas ou chaves direto no arquivo YAML. Use variáveis de pipeline:
# azure-pipelines.yml (continuação)
variables:
dockerRegistryServiceConnection: 'seu-registro-acr'
imageRepository: 'seu-app'
containerRegistry: 'seuregistry.azurecr.io'
tag: '$(Build.BuildId)'
# Sensitive variables não devem ser declaradas aqui,
# mas sim em Library > Secure Files ou Variable Groups
steps:
- task: Docker@2
displayName: Build e Push Imagem
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
latest
No Azure DevOps, você cria uma "Variable Group" no Pipeline > Library com suas variáveis sensíveis (senhas, tokens), e referencia:
variables:
- group: 'production-secrets' # Criada na UI
Integrando AKS, Pipelines e Resource Groups: Um Fluxo Completo
Até aqui você entendeu cada peça isoladamente. Agora vamos ver como elas se conectam em um fluxo real de DevOps. Você tem um repositório com código, um pipeline que builda uma imagem Docker, um registro de container que armazena a imagem, um cluster AKS que roda a aplicação, e tudo organizado dentro de um Resource Group no Azure.
O fluxo típico é: você faz git push do seu código → Azure Pipelines detecta a mudança → compila e testa o código → builda uma imagem Docker → envia para ACR → executa testes de integração → faz deploy automático no AKS. Se algo falhar em qualquer etapa, o pipeline para e você é notificado. Se tudo passar, sua aplicação atualizada está rodando em produção em minutos.
Exemplo de Pipeline End-to-End
# azure-pipelines.yml completo com teste e deploy
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
dockerRegistryServiceConnection: 'seu-acr-connection'
imageRepository: 'minha-app'
containerRegistry: 'seuregistry.azurecr.io'
dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
tag: '$(Build.BuildId)'
kubernetesServiceConnection: 'cluster-produção'
resourceGroupName: 'rg-produção-aks'
clusterName: 'cluster-produção'
stages:
- stage: Build
displayName: Build e Testes
jobs:
- job: TestAndBuild
displayName: Executar Testes e Build
steps:
# Step 1: Checkout do código (automático, mas explícito é melhor)
- checkout: self
# Step 2: Setup Node.js (ou qualquer linguagem que você use)
- task: NodeTool@0
inputs:
versionSpec: '18.x'
# Step 3: Instalar dependências e rodar testes
- script: |
npm install
npm run test
npm run lint
displayName: 'Instalar dependências e rodar testes'
# Step 4: Build da aplicação
- script: npm run build
displayName: 'Build da aplicação'
# Step 5: Build e Push da imagem Docker
- task: Docker@2
displayName: 'Build e Push da imagem Docker'
inputs:
command: buildAndPush
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
latest
- stage: Deploy
displayName: Deploy para AKS
dependsOn: Build
condition: succeeded()
jobs:
- deployment: DeployToProduction
displayName: Deploy em Produção
environment: 'production'
strategy:
runOnce:
deploy:
steps:
# Step 1: Baixar manifests publicados no build anterior
- download: current
artifact: manifests
# Step 2: Substituir tag da imagem nos manifests
- task: KubernetesManifest@0
displayName: 'Bake manifests'
name: bake
inputs:
action: 'bake'
renderingEngine: 'kustomize'
kustomizationPath: '$(Pipeline.Workspace)/manifests/kustomize'
# Step 3: Deploy no AKS
- task: KubernetesManifest@0
displayName: 'Deploy no AKS'
inputs:
action: 'deploy'
kubernetesServiceConnection: $(kubernetesServiceConnection)
namespace: 'default'
manifests: $(bake.manifestsBundle)
# Step 4: Verificar status do deployment
- script: |
kubectl rollout status deployment/minha-aplicacao -n default --timeout=5m
displayName: 'Aguardar Deployment estar pronto'
Monitorando e Troubleshooting
Depois que seu pipeline deploya, você precisa saber se a aplicação está saudável. Use esses comandos para investigar:
# Ver status dos pods
kubectl get pods -n default
kubectl describe pod <pod-name> -n default
# Ver logs da aplicação
kubectl logs deployment/minha-aplicacao -n default --tail=100
kubectl logs deployment/minha-aplicacao -n default -f # -f para seguir em tempo real
# Verificar eventos recentes
kubectl get events -n default --sort-by='.lastTimestamp'
# Acessar um pod interativamente (útil para debug)
kubectl exec -it <pod-name> -n default -- /bin/sh
# Ver métricas de recursos
kubectl top nodes
kubectl top pods -n default
# Verificar status do deployment
kubectl rollout status deployment/minha-aplicacao -n default
kubectl rollout history deployment/minha-aplicacao -n default
Conclusão
Você aprendeu que Resource Groups são a fundação organizacional—eles agrupam logicamente todos os seus recursos Azure, permitem controle de acesso centralizado, e facilitam limpeza e rastreamento de custos. Uma boa estratégia de nomeação e tags em Resource Groups economiza horas de troubleshooting depois.
AKS abstrai complexidade de Kubernetes mantendo você focado em aplicações, não em infraestrutura. Node pools permitem customização de cargas de trabalho (GPU, memória, CPU) sem precisar de múltiplos clusters. Auto-scaling garante que você não desperdice recursos nem fique sem capacidade.
Azure Pipelines orquestra o fluxo inteiro—de código para produção—removendo trabalho manual e tornando deploys repetíveis, rastreáveis e seguro. Combinados, esses três serviços formam uma plataforma de DevOps robusta que cresce com sua organização, desde startups até enterprises.
O próximo passo é praticar: crie um cluster AKS, configure um pipeline simples, e observe como uma mudança no seu código percorre automaticamente todo o caminho até produção. Erros acontecem, e esse é o valor real—quando você consegue iterar rápido e com segurança.