Nesta aula, vamos mergulhar nos conceitos centrais do Kubernetes: Pods e workloads. Pods são a menor unidade de computação que pode ser criada e gerenciada no Kubernetes, enquanto workloads (como Deployments e ReplicaSets) são abstrações que garantem que seus aplicativos sejam executados de forma confiável e escalável. Compreender esses elementos é essencial para qualquer profissional de DevOps que deseja orquestrar contêineres em produção.

Vamos explorar desde a definição de um Pod, passando por como os Deployments gerenciam réplicas e atualizações, até o ciclo de vida de um Pod. Ao final, você terá uma base sólida para criar e operar aplicações no Kubernetes.

Pods

Um Pod é a menor e mais simples unidade no modelo de objetos do Kubernetes. Ele representa um processo em execução no cluster. Um Pod encapsula um ou mais contêineres, armazenamento, endereço IP único e opções que governam como os contêineres devem ser executados. Pods são projetados para suportar múltiplos contêineres que precisam compartilhar recursos e cooperar (por exemplo, um contêiner sidecar que coleta logs do contêiner principal).

Na prática, você raramente cria Pods diretamente. Em vez disso, usa workloads como Deployments ou StatefulSets que gerenciam Pods de forma declarativa. No entanto, é crucial entender os Pods porque todos os outros recursos trabalham com eles. Um Pod é efêmero: se ele falhar ou for excluído, ele não é recriado automaticamente, a menos que seja gerenciado por um controlador.

Exemplo de definição de um Pod simples:

apiVersion: v1
kind: Pod
metadata:
  name: meu-pod
spec:
  containers:
  - name: nginx
    image: nginx:latest
    ports:
    - containerPort: 80

Para criar o Pod, use o comando kubectl apply -f pod.yaml. Para ver os Pods: kubectl get pods.

Deployments

Um Deployment é um controlador que gerencia Pods e ReplicaSets. Ele fornece atualizações declarativas para Pods e ReplicaSets, permitindo que você descreva o estado desejado e o Deployment altere o estado atual para o desejado. Isso inclui criar novos ReplicaSets, dimensionar réplicas e fazer rollbacks para versões anteriores.

Os Deployments são o workload mais comum para aplicações stateless, como servidores web e APIs. Eles garantem que um número especificado de réplicas de um Pod esteja sempre em execução. Se um Pod falhar, o Deployment cria um novo. Além disso, você pode fazer atualizações contínuas (rolling updates) sem tempo de inatividade.

Exemplo de Deployment:

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

Com esse Deployment, o Kubernetes garante que 3 réplicas do Pod estejam sempre rodando. Se um Pod morrer, o ReplicaSet (gerenciado pelo Deployment) cria um novo.

ReplicaSets

Um ReplicaSet é um controlador que garante que um número especificado de réplicas de um Pod esteja em execução. Ele é o mecanismo subjacente que os Deployments usam para manter a disponibilidade. O ReplicaSet monitora os Pods e, se algum for excluído ou falhar, ele cria um novo para manter a contagem desejada.

Embora você possa criar ReplicaSets diretamente, é mais comum usá-los indiretamente por meio de Deployments. Os Deployments gerenciam ReplicaSets e fornecem recursos adicionais, como atualizações e rollbacks. Se você criar um ReplicaSet diretamente, não terá esses recursos.

Exemplo de ReplicaSet:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: meu-replicaset
spec:
  replicas: 2
  selector:
    matchLabels:
      app: meu-app
  template:
    metadata:
      labels:
        app: meu-app
    spec:
      containers:
      - name: nginx
        image: nginx:latest

Na prática, você pode inspecionar os ReplicaSets criados por um Deployment com kubectl get replicasets.

Ciclo de vida

O ciclo de vida de um Pod é composto por várias fases: Pending, Running, Succeeded, Failed e Unknown. Quando um Pod é criado, ele entra em Pending até que o kubelet o agende e os contêineres sejam iniciados. Em seguida, ele vai para Running. Se o Pod concluir sua execução com sucesso (todos os contêineres terminam com código 0), ele vai para Succeeded; se algum contêiner falhar, vai para Failed. A fase Unknown ocorre quando o estado não pode ser obtido.

Além das fases, os Pods têm condições que fornecem mais detalhes: PodScheduled, Ready, Initialized e ContainersReady. Essas condições ajudam a diagnosticar problemas. Por exemplo, se um Pod está em Pending por muito tempo, pode ser falta de recursos ou um problema de agendamento.

Para ver o ciclo de vida de um Pod, use kubectl describe pod <nome> ou kubectl get pod -w para observar as mudanças em tempo real. Entender o ciclo de vida é crucial para depurar aplicações e configurar probes de readiness e liveness.

Boas práticas e observações finais

Ao trabalhar com Pods e workloads, siga estas boas práticas: sempre use Deployments em vez de Pods soltos para garantir alta disponibilidade; defina recursos (requests e limits) para cada contêiner; use labels e selectors de forma consistente; configure probes de readiness e liveness para que o Kubernetes saiba quando um Pod está pronto para receber tráfego; e prefira usar namespaces para organizar ambientes.

Além disso, evite criar Pods diretamente em produção. Use workloads que ofereçam auto-recuperação e escalabilidade. Para aplicações stateful, considere StatefulSets. E, por fim, sempre revise os logs e eventos para entender o comportamento do cluster.

Referências

Exercícios

  1. Crie um arquivo YAML para um Pod que execute a imagem nginx:latest e exponha a porta 80. Nomeie o Pod como meu-nginx e aplique-o no cluster. Verifique se o Pod está rodando.
  2. ✓ Resposta: Crie um arquivo pod.yaml com o conteúdo:
    apiVersion: v1
    kind: Pod
    metadata:
      name: meu-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
    
    Aplique com kubectl apply -f pod.yaml e verifique com kubectl get pods.
  3. Crie um Deployment chamado app-deployment com 3 réplicas usando a imagem nginx:1.25. Defina o seletor como app: web e a label do template como app: web. Aplique o Deployment e liste os Pods.
  4. ✓ Resposta: Crie um arquivo deployment.yaml com:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: app-deployment
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: web
      template:
        metadata:
          labels:
            app: web
        spec:
          containers:
          - name: nginx
            image: nginx:1.25
            ports:
            - containerPort: 80
    
    Aplique com kubectl apply -f deployment.yaml e liste os Pods com kubectl get pods.
  5. Explique a diferença entre um Pod e um ReplicaSet. Por que você normalmente não criaria um ReplicaSet diretamente em produção?
  6. ✓ Resposta: Um Pod é a unidade básica que encapsula um ou mais contêineres. Um ReplicaSet é um controlador que garante que um número específico de réplicas de um Pod esteja em execução. Você não criaria um ReplicaSet diretamente em produção porque ele carece de recursos como atualizações contínuas e rollbacks, que são fornecidos por um Deployment. O Deployment gerencia ReplicaSets e fornece uma abstração mais alta.
  7. Descreva as fases do ciclo de vida de um Pod e dê um exemplo de quando um Pod entra na fase Failed.
  8. ✓ Resposta: As fases são: Pending, Running, Succeeded, Failed e Unknown. Um Pod entra em Failed quando um ou mais de seus contêineres terminam com código de saída diferente de zero. Por exemplo, se um contêiner executar um comando que retorna erro, o Pod será marcado como Failed.
  9. Como você pode verificar o ciclo de vida de um Pod em execução? Descreva os comandos e o que eles mostram.
  10. ✓ Resposta: Use kubectl get pod <nome> para ver o status resumido e kubectl describe pod <nome> para ver detalhes, incluindo condições e eventos. Para observar mudanças em tempo real, use kubectl get pod -w.