DevOps Admin

Pods, Deployments e ReplicaSets em Kubernetes na Prática Já leu

Entendendo a Arquitetura de Containers no Kubernetes Antes de mergulharmos em Pods, Deployments e ReplicaSets, é fundamental entender que Kubernetes não trabalha diretamente com containers Docker. Em vez disso, ele abstrai a complexidade através de objetos que gerenciam containers em escala. O Kubernetes foi projetado para orquestrar containers, garantir alta disponibilidade, balanceamento de carga e escalabilidade automática. Esses três componentes (Pods, Deployments e ReplicaSets) são os pilares dessa orquestração e trabalham em conjunto de forma hierárquica. A beleza do Kubernetes está justamente em camadas de abstração que facilitam o trabalho do desenvolvedor e do operador. Você não precisa pensar em máquinas individuais ou em como replicar manualmente um container quando ele falha. O Kubernetes faz isso por você, e compreender como funciona essa orquestração é a chave para dominar a plataforma. Pods: O Menor Recurso Computável do Kubernetes O que é um Pod? Um Pod é a menor unidade de deployment no Kubernetes. Diferente do que muitos iniciantes pensam, um

Entendendo a Arquitetura de Containers no Kubernetes

Antes de mergulharmos em Pods, Deployments e ReplicaSets, é fundamental entender que Kubernetes não trabalha diretamente com containers Docker. Em vez disso, ele abstrai a complexidade através de objetos que gerenciam containers em escala. O Kubernetes foi projetado para orquestrar containers, garantir alta disponibilidade, balanceamento de carga e escalabilidade automática. Esses três componentes (Pods, Deployments e ReplicaSets) são os pilares dessa orquestração e trabalham em conjunto de forma hierárquica.

A beleza do Kubernetes está justamente em camadas de abstração que facilitam o trabalho do desenvolvedor e do operador. Você não precisa pensar em máquinas individuais ou em como replicar manualmente um container quando ele falha. O Kubernetes faz isso por você, e compreender como funciona essa orquestração é a chave para dominar a plataforma.

Pods: O Menor Recurso Computável do Kubernetes

O que é um Pod?

Um Pod é a menor unidade de deployment no Kubernetes. Diferente do que muitos iniciantes pensam, um Pod não é um container — é um wrapper ao redor de um ou mais containers que compartilham recursos de rede e armazenamento. Na maioria dos casos, você terá um container por Pod, mas existem cenários onde múltiplos containers em um mesmo Pod faz sentido (padrão sidecar, por exemplo).

Todos os containers dentro de um Pod compartilham o mesmo namespace de rede, o que significa que eles têm o mesmo endereço IP e podem se comunicar via localhost usando portas diferentes. Além disso, podem compartilhar volumes de armazenamento, facilitando a troca de dados. Um Pod é efêmero — quando ele morre, desaparece. Você nunca deve criar Pods manualmente em produção; sempre os gerencie através de controllers como Deployments e ReplicaSets.

Criando um Pod Simples

Vejamos um exemplo prático de um Pod rodando uma aplicação Nginx:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  namespace: default
  labels:
    app: web
spec:
  containers:
  - name: nginx
    image: nginx:1.21
    ports:
    - containerPort: 80
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

Para criar esse Pod no seu cluster, você salvaria esse arquivo como nginx-pod.yaml e executaria:

kubectl apply -f nginx-pod.yaml

Para verificar se o Pod foi criado com sucesso:

kubectl get pods
kubectl describe pod nginx-pod

Um Pod com Múltiplos Containers (Padrão Sidecar)

Às vezes, você pode precisar de um container auxiliar que trabalhe junto com o principal. Neste exemplo, temos uma aplicação que precisa fazer logging centralizado:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  containers:
  - name: app
    image: nginx:latest
    ports:
    - containerPort: 80
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  - name: log-collector
    image: busybox:latest
    command: ['sh', '-c', 'tail -f /var/log/nginx/access.log']
    volumeMounts:
    - name: shared-logs
      mountPath: /var/log/nginx
  volumes:
  - name: shared-logs
    emptyDir: {}

Nesse padrão, o container log-collector monitora logs gerados pelo Nginx, ambos compartilhando o volume shared-logs. Essa é uma forma elegante de separar responsabilidades sem criar overhead de comunicação por rede.

ReplicaSets: Garantindo Disponibilidade

Introdução aos ReplicaSets

Um ReplicaSet é um controller que garante que um número específico de réplicas de um Pod estejam sempre rodando. Se um Pod falha, o ReplicaSet automaticamente cria um novo para manter o número desejado. Isso garante alta disponibilidade e tolerância a falhas. Um ReplicaSet utiliza um seletor de labels para identificar quais Pods ele gerencia, tornando a gestão dinâmica e flexível.

Embora você possa usar ReplicaSets diretamente, a maioria das aplicações modernas usam Deployments, que são um nível a mais de abstração sobre ReplicaSets e fornecem atualizações controladas (rolling updates). Porém, entender ReplicaSets é essencial para compreender como o Kubernetes mantém suas aplicações funcionando.

Criando um ReplicaSet

Aqui está um ReplicaSet prático que mantém 3 réplicas de um servidor web:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx-replicaset
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      containers:
      - name: nginx
        image: nginx:1.21
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"

Aplicando esse ReplicaSet:

kubectl apply -f nginx-replicaset.yaml

Verificando o status:

kubectl get replicasets
kubectl get pods -l app=web-server

Você verá 3 Pods sendo gerenciados automaticamente. Se você deletar um Pod manualmente:

kubectl delete pod <nome-do-pod>

O ReplicaSet imediatamente criará um novo Pod para manter as 3 réplicas ativas.

Escalando um ReplicaSet

Uma das grandes vantagens é a escalabilidade dinâmica. Para aumentar para 5 réplicas:

kubectl scale replicaset nginx-replicaset --replicas=5

Ou edite o arquivo YAML diretamente e reaplique:

kubectl edit replicaset nginx-replicaset

Mude o campo replicas para 5 e salve. O Kubernetes ajustará automaticamente.

Deployments: Orquestração Inteligente e Atualizações

O Poder dos Deployments

Um Deployment é a abstração mais alta e mais usada no Kubernetes. Ele gerencia um ReplicaSet, que por sua vez gerencia os Pods. A grande vantagem é que Deployments facilitam atualizações de aplicações de forma segura e controlada. Você pode fazer rolling updates, onde as novas versões são implantadas gradualmente enquanto as antigas continuam servindo tráfego. Se algo der errado, você pode fazer rollback instantaneamente.

Deployments também fornecem histórico de revisões, permitindo voltar para qualquer versão anterior da sua aplicação. Além disso, garantem que o número desejado de réplicas esteja sempre disponível, mesmo durante atualizações. Na prática, 99% do tempo você usará Deployments em vez de ReplicaSets diretamente.

Criando seu Primeiro Deployment

Vejamos um Deployment funcional com uma aplicação real:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
  namespace: default
  labels:
    app: myapp
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
        version: v1
    spec:
      containers:
      - name: myapp
        image: nginx:1.21
        ports:
        - containerPort: 80
          name: http
        env:
        - name: ENVIRONMENT
          value: "production"
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5
        resources:
          requests:
            memory: "64Mi"
            cpu: "250m"
          limits:
            memory: "128Mi"
            cpu: "500m"

Criando o Deployment:

kubectl apply -f app-deployment.yaml

Verificando o status:

kubectl get deployments
kubectl get replicasets
kubectl get pods

Você verá a hierarquia: 1 Deployment gerenciando 1 ReplicaSet que gerencia 3 Pods.

Rolling Update: Atualizando sua Aplicação

Agora vem a magia. Você quer atualizar a imagem do Nginx para a versão 1.22. Em vez de derrubar tudo e reiniciar, o Kubernetes faz isso graciosamente:

kubectl set image deployment/app-deployment myapp=nginx:1.22 --record

O comando --record registra essa mudança no histórico de revisões. Observe o que acontece:

kubectl rollout status deployment/app-deployment

Você verá os Pods sendo atualizados gradualmente. Nunca há downtime. Se você quiser ver mais detalhes:

kubectl describe deployment app-deployment

Rollback: Voltando para a Versão Anterior

Se algo deu errado com a versão 1.22, você pode voltar instantaneamente:

kubectl rollout undo deployment/app-deployment

Para ver o histórico de revisões:

kubectl rollout history deployment/app-deployment

Para voltar para uma revisão específica:

kubectl rollout undo deployment/app-deployment --to-revision=1

Configurando a Estratégia de Atualização

No exemplo anterior, usamos RollingUpdate com maxSurge: 1 e maxUnavailable: 1. Isso significa: crie no máximo 1 Pod novo além das 3 replicas, e mantenha no máximo 1 Pod indisponível. Você pode ajustar isso conforme sua necessidade:

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 2           # até 2 Pods além do desejado
    maxUnavailable: 0     # nunca deixe Pods indisponíveis

Ou use a estratégia Recreate para ambientes de teste:

strategy:
  type: Recreate

Isso derruba todos os Pods antigos e cria novos, causando downtime breve mas garantindo que apenas uma versão rode de cada vez.

Probes e Healthchecks: Mantendo sua Aplicação Saudável

Liveness e Readiness Probes

Para que o Kubernetes gerencie adequadamente seus Pods, você precisa dizer a ele quando um Pod está saudável e pronto para receber tráfego. Existem dois tipos principais de probes:

Liveness Probe: Detecta quando um Pod travou e precisa ser reiniciado. Se a probe falhar, o Kubernetes derruba o Pod e cria um novo.

Readiness Probe: Determina se um Pod está pronto para receber tráfego. Pods não prontos são temporariamente removidos do load balancer.

Aqui está um exemplo completo com ambas as probes:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: health-check-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: node:16
        command: ["node", "app.js"]
        ports:
        - containerPort: 3000

        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3

        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 2

Neste exemplo, a aplicação Node.js precisa responder com sucesso no endpoint /health a cada 10 segundos. Se falhar 3 vezes consecutivas, o Pod é reiniciado. Além disso, /ready indica se a aplicação está inicializada e pronta para receber requisições.

Casos de Uso Práticos: Quando Usar Cada Um

Pods Isolados: Raramente em Produção

Você criaria um Pod diretamente apenas em cenários de teste, debug ou em jobs únicos que não precisam de replicação. Na maioria das vezes, evite. O exemplo que mostramos no início foi apenas para fins educacionais.

ReplicaSets: Quando Você Quer Controle Fino

Use ReplicaSets quando precisar apenas de replicação simples, sem atualizações controladas. Cenários raros em produção, pois Deployments cobrem 99% dos casos. Você poderia usar ReplicaSets se tiver uma aplicação stateful que não pode ter rolling updates complexas, mas mesmo assim, considere usar StatefulSets (que é outro tópico).

Deployments: A Escolha Padrão

Para 99% das aplicações, use Deployments. Eles fornecem replicação, high availability, rolling updates, rollback automático e histórico. Quer fazer deploy de uma nova versão? Deployments. Quer escalar sua aplicação? Deployments. Quer garantir que sempre haja 3 instâncias rodando? Deployments.

Aqui está um exemplo realista completo que você poderia usar em produção:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: production-api
  namespace: production
  labels:
    app: api
    environment: prod
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
        environment: prod
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - api
              topologyKey: kubernetes.io/hostname

      containers:
      - name: api
        image: myregistry.azurecr.io/myapp:v1.2.3
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          name: http

        env:
        - name: LOG_LEVEL
          value: "info"
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: connection-string

        livenessProbe:
          httpGet:
            path: /api/health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
          failureThreshold: 3

        readinessProbe:
          httpGet:
            path: /api/ready
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
          failureThreshold: 2

        resources:
          requests:
            memory: "256Mi"
            cpu: "500m"
          limits:
            memory: "512Mi"
            cpu: "1000m"

        securityContext:
          runAsNonRoot: true
          runAsUser: 1000
          allowPrivilegeEscalation: false

Neste exemplo, note que:

  • Usamos affinity para distribuir os Pods em diferentes nós
  • Injetamos secrets (credenciais de banco de dados) de forma segura
  • Definimos limites de recursos para evitar que a aplicação consuma todos os recursos do nó
  • Configuramos probes apropriadas para detectar falhas rapidamente
  • Usamos imagens de um registry privado com imagePullPolicy: Always

Debugging e Monitoramento

Comandos Essenciais

Quando algo dá errado, você precisa saber como investigar. Aqui estão os comandos mais úteis:

# Ver logs da aplicação
kubectl logs <nome-do-pod>
kubectl logs deployment/app-deployment -c container-name

# Acompanhar logs em tempo real
kubectl logs -f pod/app-deployment-xxxxx

# Execar comando dentro do container
kubectl exec -it <nome-do-pod> -- /bin/bash

# Ver eventos do cluster
kubectl describe pod <nome-do-pod>
kubectl describe deployment app-deployment

# Verificar por quais nós os Pods estão distribuídos
kubectl get pods -o wide

# Debug completo de um Deployment
kubectl get all -l app=myapp

Conclusão

Dominar Pods, ReplicaSets e Deployments é fundamental para trabalhar efetivamente com Kubernetes. A chave é entender a hierarquia: Deployments gerenciam ReplicaSets, que gerenciam Pods, que contêm containers. Na prática, você quase nunca criará Pods ou ReplicaSets manualmente em produção — use sempre Deployments, que fornecem atualizações seguras, rollback automático e escalabilidade sem downtime. Por fim, sempre configure liveness e readiness probes para permitir que o Kubernetes gerencie sua aplicação de forma inteligente, detectando e recuperando-se automaticamente de falhas.

Referências


Artigos relacionados