0%
Introdução ao Kubernetes

Introdução

Por que orquestrar, e o que o Docker Compose não sabe fazer.

15-20 min

Introdução ao Kubernetes

Você sabe construir uma imagem e executar um contêiner. Na sua máquina, docker compose up sobe uma API, um banco de dados e um cache em poucos segundos, e tudo funciona. Então surge a pergunta que muda tudo: o que acontece quando essa aplicação precisa rodar continuamente, em várias máquinas, sem que ninguém precise acordar de madrugada para reiniciá-la?

O Compose descreve um estado desejado, mas nada o mantém ao longo do tempo. Se o processo falha, restart: always o reinicia. Se a máquina cai, nada mais reinicia coisa alguma. Se o tráfego triplica, você sobe réplicas manualmente, os endereços delas mudam e é preciso reconfigurar o reverse proxy. Se você implanta uma nova versão, há uma interrupção entre a parada da antiga e a inicialização da nova. Cada um desses problemas tem uma resposta manual óbvia. O que se torna insustentável é o acúmulo deles.

A resposta do Kubernetes não é “mais comandos”. É uma inversão de responsabilidade: você descreve o estado que deseja, de forma permanente, e um conjunto de loops de controle trabalha continuamente para que a realidade corresponda a essa descrição. Esse é o único conceito realmente estruturante do sistema: todo o resto — Pods, Deployments, Services, volumes — é apenas uma variação dessa ideia aplicada a um objeto específico.

Esta lição apresenta esse modelo e depois descreve a arquitetura de um cluster. Não por gosto de nomenclatura: saber qual componente decide o quê é o que permitirá diagnosticar problemas. Um Pod bloqueado porque o scheduler não encontra nenhum nó disponível e um Pod bloqueado porque o kubelet não consegue baixar a imagem são duas falhas que não têm a mesma causa nem o mesmo lugar onde investigar.

Imperativo versus declarativo

Com o Docker, você dá ordens. Cada comando descreve uma ação a ser executada agora:

# Impératif : je décris les actions, une par une, dans l'ordre.
docker build -t mon-api:1.2.0 .
docker run -d --name api-1 -p 8080:8080 mon-api:1.2.0
docker run -d --name api-2 -p 8081:8080 mon-api:1.2.0
docker stop api-1        # pour mettre à jour : coupure assumée
docker rm api-1
docker run -d --name api-1 -p 8080:8080 mon-api:1.3.0

Esse script funciona uma vez. Ele não diz nada sobre o que deve continuar sendo verdade. Ao lê-lo, ninguém sabe se deve haver duas réplicas ou três, nem qual versão deveria estar em execução.

Com o Kubernetes, você descreve um alvo. O arquivo abaixo não diz “inicie três contêineres”, ele diz “deve haver três réplicas desta versão, permanentemente”:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mon-api
spec:
  replicas: 3                    # état voulu, pas une action ponctuelle
  selector:
    matchLabels:
      app: mon-api
  template:
    metadata:
      labels:
        app: mon-api
    spec:
      containers:
        - name: api
          image: mon-api:1.3.0
          ports:
            - containerPort: 8080

A diferença prática é imediata. Mate um dos três contêineres: um quarto nasce alguns segundos depois, porque a contagem não corresponde mais ao alvo. Desligue um nó: as réplicas que ele hospedava são recriadas em outro lugar. Ninguém deu nenhuma ordem, um controlador apenas constatou uma divergência.

O loop de reconciliação

Este é o mecanismo central, e ele é simples:

  1. Um controlador lê o estado desejado (o que você declarou).
  2. Ele observa o estado real do cluster.
  3. Se os dois diferem, ele age para reduzir a divergência.
  4. Ele recomeça. Indefinidamente.

Existe um controlador para cada tipo de responsabilidade, e eles são propositalmente míopes: aquele que gerencia os ReplicaSets não sabe nada sobre a rede, aquele que gerencia os Services não sabe nada sobre os volumes. Cada um vigia a sua própria divergência. A orquestração global emerge desses loops independentes, não é conduzida por um único maestro.

Essa arquitetura tem uma consequência que convém aceitar cedo: o Kubernetes é assíncrono. Quando kubectl apply responde, ele não implantou nada, apenas registrou a sua intenção. O trabalho real acontece depois, e pode falhar depois. É por isso que nunca se verifica uma implantação pelo retorno do apply, mas sempre pelo estado observado:

# apply enregistre l'intention : le retour ne prouve rien sur l'exécution.
kubectl apply -f deployment.yaml

# La vérification se fait sur l'état réel, ensuite.
kubectl get deployment mon-api
kubectl get pods -l app=mon-api

# Et si un Pod ne démarre pas, la raison est dans les événements de fin de description.
kubectl describe pod mon-api-7d4b8c9f5-xk2mp

A arquitetura de um cluster

Um cluster se divide em dois papéis: o plano de controle (control plane), que decide, e os nós de trabalho (worker nodes), que executam.

O plano de controle

ComponentePapelO que isso implica em caso de falha
kube-apiserverÚnica porta de entrada. Valida e persiste todas as requisições.Nenhuma modificação é mais possível; as cargas de trabalho já iniciadas continuam rodando.
etcdBanco chave-valor que armazena o estado desejado e o estado observado.Perda do etcd sem backup = perda do cluster lógico.
kube-schedulerEscolhe em qual nó posicionar cada novo Pod.Os novos Pods permanecem em Pending.
kube-controller-managerExecuta os loops de reconciliação.Sem mais autorrecuperação: os Pods mortos não são substituídos.

O ponto notável: kubectl só fala com o API server. Ele não abre nenhuma conexão com um nó e não controla nenhum contêiner. Toda a segurança e toda a rastreabilidade passam, portanto, por um único ponto.

Os nós de trabalho

Em cada nó rodam três elementos:

  • kubelet: o agente que recebe a lista de Pods a executar no seu nó, pede ao runtime que os inicie, executa as sondas de saúde e reporta o estado.
  • runtime de contêineres: containerd ou CRI-O, na maioria das vezes. É ele que baixa as imagens e inicia os processos. Suas imagens Docker funcionam sem modificação: elas seguem o formato OCI, que esses runtimes sabem ler.
  • kube-proxy: programa as regras de rede do nó para que o endereço estável de um Service alcance os Pods corretos.
# Voir les nœuds et leur état vu du plan de contrôle
kubectl get nodes

# Détail d'un nœud : capacité, ressources déjà réservées, conditions
kubectl describe node minikube

# Les composants du plan de contrôle sont eux-mêmes des Pods, dans kube-system
kubectl get pods -n kube-system

Este último comando merece uma pausa: o plano de controle é administrado pelo próprio Kubernetes. Não é um capricho, é o que torna seus componentes observáveis e reparáveis com as mesmas ferramentas das suas aplicações.

O Pod, e por que ele não é um contêiner

O Kubernetes não implanta contêineres. Ele implanta Pods. Um Pod é um grupo de um ou mais contêineres que compartilham o mesmo espaço de rede e podem compartilhar volumes. Os contêineres de um mesmo Pod se comunicam via localhost e são sempre alocados no mesmo nó.

apiVersion: v1
kind: Pod
metadata:
  name: demo-pod
  labels:
    app: demo
spec:
  containers:
    - name: web
      image: nginx:1.27-alpine
      ports:
        - containerPort: 80

Por que essa camada intermediária? Porque algumas necessidades são inseparáveis do processo principal: um coletor de logs que lê o mesmo diretório, um proxy que termina o TLS antes da aplicação. Tratá-los como contêineres independentes obrigaria a garantir a colocalização deles por meios indiretos. O Pod torna essa garantia explícita.

Segundo ponto, mais importante na prática: um Pod é descartável. Ele não tem um nome estável, seu endereço IP muda a cada recriação e nada sobrevive ao seu desaparecimento. Por isso, quase nunca se cria um Pod diretamente — o manifesto acima é um exemplo pedagógico, não um modelo de produção. Cria-se um Deployment, que cria e substitui os Pods para você. A lição 3 detalha essa cadeia.

O que você ganha, o que você paga

O Kubernetes oferece, sem que você precise escrever:

  • a autorrecuperação: Pods e nós com falha são substituídos automaticamente;
  • a descoberta de serviços: um nome DNS estável na frente de um conjunto de Pods que mudam o tempo todo;
  • as atualizações progressivas com rollback, sem interrupção;
  • a escalabilidade manual ou automática conforme a carga medida;
  • a distribuição sob restrições: o scheduler posiciona os Pods de acordo com a CPU e a memória realmente disponíveis.

A autorrecuperação se verifica com uma única manipulação, e é a demonstração mais clara do modelo declarativo:

# On supprime une réplique à la main…
kubectl delete pod mon-api-7d4b8c9f5-xk2mp

# …et le compte est déjà rétabli, avec un Pod au suffixe différent.
kubectl get pods -l app=mon-api

O custo é real e precisa ser dito. O Kubernetes adiciona uma camada de abstração com sua própria complexidade: mais conceitos a conhecer, mais configuração em YAML, um cluster a manter ou a pagar e um conjunto de ferramentas de diagnóstico a aprender. Para um site institucional em uma única máquina, docker compose continua sendo a escolha certa, e afirmar o contrário seria desonesto. O Kubernetes se torna vantajoso quando você tem vários serviços, uma exigência de disponibilidade ou várias equipes que fazem deploy na mesma infraestrutura.

O vocabulário comum a todos os manifestos

Todo objeto do Kubernetes, qualquer que seja o seu tipo, é escrito com os mesmos quatro campos de primeiro nível. Reconhecê-los torna qualquer manifesto legível:

apiVersion: apps/v1      # groupe et version de l'API qui définit ce type
kind: Deployment         # le type d'objet
metadata:                # identité : nom, namespace, labels, annotations
  name: mon-api
  labels:
    app: mon-api
spec:                    # l'état voulu ; son contenu dépend du kind
  replicas: 3

Há uma única regra de apiVersion a reter para este curso, e ela evita o erro mais frequente dos iniciantes:

  • v1 para Pod, Service, ConfigMap, Secret, PersistentVolume, PersistentVolumeClaim;
  • apps/v1 para Deployment, ReplicaSet, StatefulSet, DaemonSet.

Um apiVersion: v1 em um Deployment é rejeitado pelo API server com uma mensagem pouco explícita. A lista exata para um determinado tipo pode ser lida diretamente do cluster:

# Quel apiVersion pour ce type ? La réponse vient du cluster, pas de la mémoire.
kubectl api-resources | grep -i deployment

# Documentation d'un champ, sans quitter le terminal
kubectl explain deployment.spec.strategy

kubectl explain é a ferramenta mais subutilizada do ecossistema. Ele descreve os campos da versão da API realmente instalada no seu cluster, algo que nenhum artigo de blog pode garantir.

O que o restante do curso aborda

  1. Instalação e configuração — um cluster local com minikube ou kind, kubectl, contextos e namespaces.
  2. Pods, Services e Deployments — os recursos do dia a dia, os seletores de labels, as atualizações progressivas e as sondas.
  3. ConfigMaps e Secrets — tirar a configuração das imagens, e o que “Secret” não significa.
  4. Armazenamento persistente — volumes, claims, StorageClass e StatefulSet.
  5. Implantação de aplicações complexas — multisserviços, Ingress, recursos, autoscaling, visão geral do Helm.

Todos esses objetos já são conhecidos pelo seu futuro cluster. Este comando os lista com o nome abreviado, aquele que você digitará no dia a dia:

kubectl api-resources | grep -E 'deployments|services|configmaps|secrets|persistentvolumeclaims'
# deployments   deploy   apps/v1   true   Deployment
# services      svc      v1        true   Service
# configmaps    cm       v1        true   ConfigMap

Pontos-chave

  • O Kubernetes é declarativo: você descreve um estado desejado, e loops de reconciliação o mantêm. apply registra uma intenção, não garante um resultado — a verificação é sempre feita sobre o estado observado.
  • O plano de controle decide (API server, etcd, scheduler, controller-manager), os nós executam (kubelet, runtime, kube-proxy). Saber quem faz o quê é a base do diagnóstico.
  • A unidade implantada é o Pod, não o contêiner: um grupo colocalizado que compartilha rede e volumes e, sobretudo, descartável. Ele é criado por meio de um controlador, nunca manualmente em produção.
  • Todos os manifestos compartilham apiVersion, kind, metadata, spec. Lembre-se de v1 para Pod/Service/ConfigMap/Secret/PVC e apps/v1 para Deployment/StatefulSet.
  • A orquestração tem um custo de complexidade assumido. Ela se justifica pelo número de serviços, pela exigência de disponibilidade e pelo número de equipes, não pela moda.

Referência: a documentação oficial está em francês para boa parte dos conceitos. Mantenha kubernetes.io/fr/docs/concepts/ aberto durante este curso.

Comentários

Os comentários são alimentados pelo GitHub Discussions

Conecte-se com o GitHub para participar da discussão

Link copiado!