Deployments: gerenciando pods com resiliência

1. Introdução aos Deployments

No ecossistema Kubernetes, gerenciar Pods diretamente é uma prática arriscada e pouco escalável. Pods são efêmeros por natureza — podem falhar, ser removidos por nós com problemas ou simplesmente não estar disponíveis quando necessário. É aqui que entram os Deployments.

Um Deployment é um recurso do Kubernetes que declara o estado desejado para um conjunto de Pods. Ele garante que o número correto de réplicas esteja sempre em execução, orquestra atualizações sem downtime e permite rollbacks rápidos. Em vez de criar Pods manualmente com kubectl run, você define um manifesto declarativo e o Kubernetes faz o resto.

A relação com ReplicaSets é fundamental: o Deployment cria e gerencia ReplicaSets, que por sua vez garantem a quantidade de Pods rodando. Cada atualização gera um novo ReplicaSet, permitindo rastreamento de versões e reversões.

2. Estrutura de um Manifesto de Deployment

Um manifesto de Deployment segue a estrutura padrão do Kubernetes. Os campos essenciais são:

  • apiVersion: normalmente apps/v1
  • kind: Deployment
  • metadata: nome, labels, anotações
  • spec: especificação do estado desejado

Dentro de spec, os campos mais importantes são:

  • replicas: número de Pods desejado
  • selector: labels que identificam os Pods gerenciados
  • template: modelo do Pod a ser criado

Exemplo completo:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80

Para aplicar: kubectl apply -f deployment.yaml. O Kubernetes criará 3 Pods idênticos baseados no template.

3. Atualizações Rolling Update

A estratégia padrão de atualização do Deployment é RollingUpdate. Ela substitui gradualmente os Pods antigos pelos novos, mantendo a aplicação disponível durante todo o processo.

Dois parâmetros controlam o ritmo:

  • maxSurge: número máximo de Pods extras que podem ser criados (absoluto ou percentual)
  • maxUnavailable: número máximo de Pods que podem ficar indisponíveis durante a atualização

Exemplo de configuração:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

Na prática, para atualizar a imagem:

kubectl set image deployment/nginx-deployment nginx=nginx:1.26

Acompanhe o progresso:

kubectl rollout status deployment/nginx-deployment

4. Rollback e Histórico de Revisões

Cada alteração em um Deployment gera uma nova revisão. O histórico é automaticamente mantido (por padrão, 10 revisões).

Para visualizar o histórico:

kubectl rollout history deployment/nginx-deployment

Para reverter para uma versão anterior:

kubectl rollout undo deployment/nginx-deployment

Ou para uma revisão específica:

kubectl rollout undo deployment/nginx-deployment --to-revision=2

Esse mecanismo é essencial para resiliência: se uma atualização quebrar a aplicação, o rollback é imediato.

5. Estratégias de Implantação Alternativas

Além do RollingUpdate, existe a estratégia Recreate:

spec:
  strategy:
    type: Recreate

Nesta estratégia, todos os Pods existentes são mortos antes que os novos sejam criados. Isso causa downtime, mas é útil quando:

  • A aplicação não suporta múltiplas versões rodando simultaneamente
  • O banco de dados precisa de migrações exclusivas
  • Recursos compartilhados (como volumes) não podem ser acessados por múltiplas versões

Para estratégias mais avançadas como Blue/Green e Canary, é comum usar múltiplos Deployments com serviços apontando para diferentes versões, combinados com ferramentas como Argo Rollouts ou Flagger.

6. Health Checks e Auto-Recuperação

Probes são verificações de saúde que o kubelet executa nos contêineres:

  • LivenessProbe: se falhar, o kubelet reinicia o contêiner
  • ReadinessProbe: se falhar, o Pod é removido dos endpoints de serviço

Exemplo de configuração:

spec:
  containers:
  - name: nginx
    image: nginx:1.25
    livenessProbe:
      httpGet:
        path: /healthz
        port: 80
      initialDelaySeconds: 3
      periodSeconds: 5
    readinessProbe:
      httpGet:
        path: /ready
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10

Sem probes, o Kubernetes não sabe se seu contêiner está realmente funcionando. Com eles, o sistema se recupera automaticamente de falhas.

7. Escalonamento de Pods

Escalonamento manual:

kubectl scale deployment/nginx-deployment --replicas=5

Escalonamento automático com HPA (Horizontal Pod Autoscaler):

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Para métricas customizadas (ex: requisições por segundo), é necessário instalar o Metrics Server ou adaptadores como Prometheus Adapter.

8. Boas Práticas e Troubleshooting

Versionamento de imagens: sempre use tags específicas (v1.2.3) em vez de latest. Tags imutáveis garantem que você sabe exatamente qual versão está rodando.

Recursos: defina requests e limits para todos os contêineres:

resources:
  requests:
    memory: "64Mi"
    cpu: "250m"
  limits:
    memory: "128Mi"
    cpu: "500m"

Isso evita que um Pod consuma todos os recursos do nó.

Depuração:

kubectl describe deployment nginx-deployment
kubectl get events --sort-by='.lastTimestamp'
kubectl logs -l app=nginx --tail=50
kubectl describe pod nginx-deployment-xxxxx

Eventos costumam revelar rapidamente problemas de imagem, falta de recursos ou falhas nos probes.

Referências