<h2>Azure Resource Groups: Fundação da Organização em Nuvem</h2>
<p>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.</p>
<p>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.</p>
<h3>Criando e Gerenciando Resource Groups</h3>
<p>A forma mais direta de criar um Resource Group é pela CLI do Azure. Vou mostrar um exemplo prático e funcional:</p>
<pre><code class="language-bash"># 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</code></pre>
<p>A flag <code>--location</code> é 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.</p>
<h3>Aplicando Tags e Políticas</h3>
<p>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.</p>
<pre><code class="language-bash"># 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</code></pre>
<h2>Azure Kubernetes Service (AKS): Orquestração de Contêineres Simplificada</h2>
<p>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.</p>
<p>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.</p>
<h3>Criando um Cluster AKS</h3>
<pre><code class="language-bash"># 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)</code></pre>
<p>Após a criação, você precisa configurar suas credenciais locais para interagir com o cluster:</p>
<pre><code class="language-bash"># 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</code></pre>
<p>O output do <code>kubectl get nodes</code> mostrará algo assim:</p>
<pre><code>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</code></pre>
<h3>Escalabilidade e Node Pools</h3>
<p>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:</p>
<pre><code class="language-bash"># 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</code></pre>
<p>A taint <code>gpu=true:NoSchedule</code> garante que apenas pods que tolerem essa taint sejam agendados nesse pool. Em seu YAML de deployment, você declararia:</p>
<pre><code class="language-yaml">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</code></pre>
<h2>Azure Pipelines: Automação de Build, Teste e Deploy</h2>
<p>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.</p>
<p>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 <code>azure-pipelines.yml</code>) 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.</p>
<h3>Estrutura de um Pipeline Básico</h3>
<pre><code class="language-yaml"># 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</code></pre>
<p>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 <code>dependsOn: Build</code> garante que o Deploy só aconteça se o Build tiver sucesso.</p>
<h3>Conectando Azure Pipelines ao Azure Container Registry (ACR)</h3>
<p>Você precisa de um registro privado para armazenar suas imagens Docker. Azure Container Registry é gerenciado, integrado e seguro:</p>
<pre><code class="language-bash"># 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</code></pre>
<p>A integração com <code>az aks update --attach-acr</code> é essencial: ela cria uma identidade gerenciada que permite que o AKS puxe imagens sem você precisar de senhas ou tokens.</p>
<h3>Estrutura Recomendada de Manifests Kubernetes</h3>
<p>Seus manifests (arquivos YAML) devem estar em um diretório chamado <code>manifests</code> no repositório:</p>
<pre><code class="language-yaml"># 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</code></pre>
<pre><code class="language-yaml"># 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</code></pre>
<h3>Variáveis e Secrets no Pipeline</h3>
<p>Nunca coloque senhas ou chaves direto no arquivo YAML. Use variáveis de pipeline:</p>
<pre><code class="language-yaml"># 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</code></pre>
<p>No Azure DevOps, você cria uma "Variable Group" no Pipeline > Library com suas variáveis sensíveis (senhas, tokens), e referencia:</p>
<pre><code class="language-yaml">variables:
- group: 'production-secrets' # Criada na UI</code></pre>
<h2>Integrando AKS, Pipelines e Resource Groups: Um Fluxo Completo</h2>
<p>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.</p>
<p>O fluxo típico é: você faz <code>git push</code> 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.</p>
<h3>Exemplo de Pipeline End-to-End</h3>
<pre><code class="language-yaml"># 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'</code></pre>
<h3>Monitorando e Troubleshooting</h3>
<p>Depois que seu pipeline deploya, você precisa saber se a aplicação está saudável. Use esses comandos para investigar:</p>
<pre><code class="language-bash"># 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</code></pre>
<h2>Conclusão</h2>
<p>Você aprendeu que <strong>Resource Groups são a fundação organizacional</strong>—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.</p>
<p><strong>AKS abstrai complexidade de Kubernetes</strong> 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.</p>
<p><strong>Azure Pipelines orquestra o fluxo inteiro</strong>—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.</p>
<p>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.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://learn.microsoft.com/pt-br/azure/aks/" target="_blank" rel="noopener noreferrer">Documentação oficial do Azure Kubernetes Service (AKS)</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/" target="_blank" rel="noopener noreferrer">Azure Pipelines Documentation</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal" target="_blank" rel="noopener noreferrer">Azure Resource Groups - Best Practices</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/aks/best-practices" target="_blank" rel="noopener noreferrer">Kubernetes Best Practices on Azure</a></li>
<li><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/ecosystems/kubernetes/deploy" target="_blank" rel="noopener noreferrer">CI/CD com Azure DevOps e Kubernetes</a></li>
</ul>
<p><!-- FIM --></p>