Como Usar Kubernetes: Arquitetura do Cluster, Control Plane e Worker Nodes em Produção Já leu

Introdução ao Kubernetes e Sua Arquitetura Kubernetes, frequentemente abreviado como K8s, é uma plataforma de orquestração de containers desenvolvida pelo Google e mantida pela Cloud Native Computing Foundation. Ela resolve um problema fundamental na computação moderna: como gerenciar, escalar e manter aplicações containerizadas em ambientes de produção distribuídos. A arquitetura do Kubernetes é baseada em um modelo cliente-servidor onde um cluster é dividido em dois componentes principais: o Control Plane (antes chamado de Master) e os Worker Nodes. Essa divisão permite que você execute aplicações de forma resiliente, com alta disponibilidade e escalabilidade automática. Neste artigo, vamos desmontar cada componente e entender como eles trabalham juntos para orquestrar sua infraestrutura containerizada. Arquitetura Geral do Cluster Kubernetes A Estrutura Hierárquica Um cluster Kubernetes funciona como um sistema distribuído onde o Control Plane atua como o "cérebro" do sistema, tomando decisões sobre o estado desejado dos containers, enquanto os Worker Nodes são os "músculos" que executam efetivamente os containers. A comunicação entre

Introdução ao Kubernetes e Sua Arquitetura

Kubernetes, frequentemente abreviado como K8s, é uma plataforma de orquestração de containers desenvolvida pelo Google e mantida pela Cloud Native Computing Foundation. Ela resolve um problema fundamental na computação moderna: como gerenciar, escalar e manter aplicações containerizadas em ambientes de produção distribuídos.

A arquitetura do Kubernetes é baseada em um modelo cliente-servidor onde um cluster é dividido em dois componentes principais: o Control Plane (antes chamado de Master) e os Worker Nodes. Essa divisão permite que você execute aplicações de forma resiliente, com alta disponibilidade e escalabilidade automática. Neste artigo, vamos desmontar cada componente e entender como eles trabalham juntos para orquestrar sua infraestrutura containerizada.

Arquitetura Geral do Cluster Kubernetes

A Estrutura Hierárquica

Um cluster Kubernetes funciona como um sistema distribuído onde o Control Plane atua como o "cérebro" do sistema, tomando decisões sobre o estado desejado dos containers, enquanto os Worker Nodes são os "músculos" que executam efetivamente os containers. A comunicação entre eles ocorre através de APIs RESTful e segue um padrão declarativo: você descreve o estado desejado, e o Kubernetes trabalha para alcançá-lo.

A arquitetura é completamente descentralizada em termos de execução. Se um Worker Node falha, o Control Plane detecta a falha e reconstrói os containers em outro nó saudável. Isso é possível porque o Kubernetes mantém um registro do estado desejado e constantemente verifica se a realidade corresponde a esse desejo, em um padrão conhecido como reconciliation loop.

┌─────────────────────────────────────────────────────────────┐
│                      KUBERNETES CLUSTER                      │
├────────────────────┬────────────────────────────────────────┤
│   CONTROL PLANE    │           WORKER NODES                 │
│  (Master Node)     │                                        │
│                    │  ┌──────────┐  ┌──────────┐           │
│ ┌──────────────┐   │  │ Node 1   │  │ Node 2   │           │
│ │ API Server   │   │  │ ┌──────┐ │  │ ┌──────┐ │           │
│ └──────────────┘   │  │ │Pod A │ │  │ │Pod C │ │           │
│                    │  │ ├──────┤ │  │ ├──────┤ │           │
│ ┌──────────────┐   │  │ │Pod B │ │  │ │Pod D │ │           │
│ │ Scheduler    │   │  │ └──────┘ │  │ └──────┘ │           │
│ └──────────────┘   │  └──────────┘  └──────────┘           │
│                    │                                        │
│ ┌──────────────┐   │                                        │
│ │Controller Mgr│   │                                        │
│ └──────────────┘   │                                        │
│                    │                                        │
│ ┌──────────────┐   │                                        │
│ │ etcd (DB)    │   │                                        │
│ └──────────────┘   │                                        │
└────────────────────┴────────────────────────────────────────┘

O Control Plane: O Cérebro do Cluster

Componentes Principais do Control Plane

O Control Plane é composto por vários componentes que trabalham em conjunto. O API Server é o ponto central de comunicação; toda solicitação ao cluster passa por ele, seja para criar novos recursos ou consultar o estado atual. Ele valida as requisições, autoriza as ações e persiste as mudanças no banco de dados.

O Scheduler é responsável por decidir qual Worker Node executará cada Pod. Ele analisa os requisitos de recursos (CPU, memória), constraints de afinidade e outras políticas para tomar decisões otimizadas. O Controller Manager executa diversos controladores que monitoram o estado do cluster e trabalham continuamente para manter o estado desejado. Por fim, o etcd é um banco de dados chave-valor distribuído que armazena todo o estado do cluster de forma durável.

# Exemplo: Consultando componentes do Control Plane em um cluster real
apiVersion: v1
kind: Pod
metadata:
  name: diagnostico-control-plane
  namespace: kube-system
spec:
  containers:
  - name: check-components
    image: alpine:3.18
    command:
    - sh
    - -c
    - |
      echo "=== Verificando componentes do Control Plane ==="
      # Em um cluster real, você veria pods como:
      # kube-apiserver-master-1
      # kube-scheduler-master-1
      # kube-controller-manager-master-1
      # etcd-master-1
      sleep 3600

Como o API Server Funciona

O API Server é a base de toda operação em Kubernetes. Quando você executa kubectl apply, o comando é convertido em uma requisição HTTP para o API Server. Ele valida a sintaxe YAML, verifica permissões (RBAC), aplica mutating webhooks, e finalmente armazena o recurso no etcd.

# Exemplo prático: Criar um Deployment e acompanhar o fluxo
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
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 200m
            memory: 256Mi

Quando este YAML é aplicado:
1. O API Server recebe a requisição e valida a estrutura
2. O Scheduler observa que há uma nova Deployment com 3 réplicas
3. O Scheduler atribui cada Pod a um Worker Node específico
4. O kubelet em cada nó recebe a instrução e puxa a imagem Docker
5. O container é iniciado e o etcd registra o estado

O etcd: Persistência do Estado

O etcd é o coração da durabilidade do cluster. Todo recurso criado no Kubernetes é armazenado aqui. É um banco de dados chave-valor distribuído que oferece forte consistência. Nunca perca seus dados do etcd em produção; implemente snapshots regulares e replicação entre múltiplos nós do Control Plane.

# Exemplo: Fazendo backup do etcd (executar no master)
# Nota: Em clusters gerenciados (EKS, GKE, AKS), isso é automatizado
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-snapshot.db \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

# Verificando o snapshot
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-snapshot.db

Worker Nodes: Onde a Ação Acontece

Componentes de um Worker Node

Cada Worker Node é uma máquina (física ou virtual) que executa containers. O componente mais importante é o kubelet, um agente que roda em cada nó e é responsável por garantir que os containers especificados estão rodando. Ele comunica-se constantemente com o API Server para obter as instruções e relata o status.

O kube-proxy gerencia a rede no nó. Ele implementa o Kubernetes Service, criando regras de firewall e redirecionamento de tráfego para que os Pods possam se comunicar entre si e com o mundo exterior. O container runtime é o mecanismo que realmente executa os containers; pode ser Docker, containerd, CRI-O ou outro compatível com a Container Runtime Interface (CRI).

# Exemplo: Inspecionando um Worker Node
apiVersion: v1
kind: Node
metadata:
  name: worker-node-1
  labels:
    kubernetes.io/os: linux
    node.kubernetes.io/instance-type: t3.medium
spec:
  # Taints são restrições que impedem pods de serem agendados
  taints:
  - key: dedicated
    value: worker
    effect: NoSchedule
  # Podemos adicionar labels customizados
  labels:
    disktype: ssd
    node-role: compute-heavy
status:
  capacity:
    cpu: "2"
    memory: "4Gi"
    pods: "110"
  allocatable:
    cpu: "1900m"
    memory: "3800Mi"
    pods: "110"
  conditions:
  - type: Ready
    status: "True"
    lastHeartbeatTime: "2024-01-15T10:30:00Z"

O Kubelet: O Agente Local

O kubelet é um daemon que roda em cada nó e sincroniza constantemente com o API Server. Ele recebe especificações de Pods, executa-as através do container runtime, monitora sua saúde e relata status. Se um container falha, o kubelet tenta reiniciá-lo conforme a política de restart.

# Exemplo: Verificar logs do kubelet em um nó
# SSH no worker node
ssh ubuntu@worker-node-1

# Visualizar status do kubelet
sudo systemctl status kubelet

# Ver logs em tempo real
sudo journalctl -u kubelet -f

# Verificar configuração do kubelet
cat /var/lib/kubelet/kubeconfig.conf

# Reiniciar o kubelet (cuidado em produção!)
sudo systemctl restart kubelet

Networking e o kube-proxy

O kube-proxy implementa a abstração de Service do Kubernetes. Quando você cria um Service, o kube-proxy cria regras de iptables (ou IPVS em clusters maiores) que redirecionam o tráfego para os Pods corretos. Isso permite comunicação entre Pods sem conhecer seus IPs específicos.

# Exemplo: Service e como o kube-proxy roteia tráfego
apiVersion: v1
kind: Service
metadata:
  name: web-service
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Pod
metadata:
  name: web-pod-1
  labels:
    app: web
spec:
  containers:
  - name: web
    image: nginx:1.25
    ports:
    - containerPort: 8080

Quando o Service é criado, o kube-proxy em cada nó cria regras que fazem com que requisições para web-service:80 sejam redirecionadas para um dos Pods rotulados com app: web na porta 8080.

Comunicação Entre Componentes

O Fluxo de uma Requisição do Usuário

Quando você executa kubectl apply -f deployment.yaml, aqui está o que acontece internamente. O kubectl envia a requisição YAML para o API Server no Control Plane. O API Server valida a requisição, aplica políticas de admissão e armazena o recurso no etcd. Simultaneamente, o Deployment Controller observa a mudança e cria ReplicaSets conforme especificado. O ReplicaSet Controller cria Pods conforme a réplica desejada. O Scheduler observa os Pods pendentes e atribui-os aos Worker Nodes. Por fim, o kubelet em cada nó detecta que há um Pod assignado a ele e executa o container.

# Exemplo: Acompanhar este fluxo em tempo real
# Terminal 1: Observar eventos do cluster
kubectl get events --all-namespaces --watch

# Terminal 2: Criar uma deployment
kubectl apply -f deployment.yaml

# Terminal 3: Observar o status dos pods
kubectl get pods --watch

# Você verá a progressão: Pending → ContainerCreating → Running

Heartbeat e Health Checks

O kubelet periodicamente envia informações sobre o nó e os Pods para o API Server. Se um nó não enviar heartbeat por mais de alguns minutos, o Control Plane marca-o como NotReady e começa a reagendar seus Pods em outros nós. Dentro dos Pods, você pode configurar liveness probes para detectar aplicações travadas e restart probes para recuperar-se de falhas.

# Exemplo: Configurar health checks em um Pod
apiVersion: v1
kind: Pod
metadata:
  name: app-com-health-checks
spec:
  containers:
  - name: app
    image: my-app:1.0
    ports:
    - containerPort: 8000

    # Liveness probe: reinicia o container se falhar
    livenessProbe:
      httpGet:
        path: /health
        port: 8000
      initialDelaySeconds: 5
      periodSeconds: 10
      timeoutSeconds: 2
      failureThreshold: 3

    # Readiness probe: remove do tráfego se falhar
    readinessProbe:
      httpGet:
        path: /ready
        port: 8000
      initialDelaySeconds: 3
      periodSeconds: 5

    # Startup probe: aguarda aplicação iniciar
    startupProbe:
      httpGet:
        path: /startup
        port: 8000
      failureThreshold: 30
      periodSeconds: 10

Multi-Master: Alta Disponibilidade do Control Plane

Configuração de Redundância

Em ambientes de produção, nunca execute um Control Plane com apenas um nó. Se aquele nó falhar, todo seu cluster fica indisponível. A melhor prática é ter no mínimo 3 nós de Control Plane para garantir quórum em caso de falhas. Todos os nós do Control Plane executam os mesmos componentes, mas o etcd é replicado entre eles para garantir consistência.

# Exemplo: Verificar nós do Control Plane em um cluster
# Execute: kubectl get nodes -L node-role.kubernetes.io/control-plane

# Saída esperada:
# NAME           STATUS   ROLES                  AGE
# master-1       Ready    control-plane,master   30d
# master-2       Ready    control-plane,master   30d
# master-3       Ready    control-plane,master   30d
# worker-1       Ready    <none>                 25d
# worker-2       Ready    <none>                 25d

Load Balancing do API Server

Para que os clientes (como kubectl) se conectem ao Control Plane sem conhecer qual nó master está saudável, você precisa de um load balancer na frente dos API Servers. Em ambientes cloud, use os load balancers nativos (AWS ELB, Azure Load Balancer, etc.). Em on-premise, considere HAProxy ou similares.

# Exemplo: Configuração de HAProxy para load balancer do K8s API
# /etc/haproxy/haproxy.cfg
global
  log /dev/log local0
  maxconn 4096

defaults
  mode tcp
  timeout connect 10s
  timeout client 30s
  timeout server 30s

frontend kubernetes-api
  bind 10.0.0.10:6443
  mode tcp
  default_backend kubernetes-api-backend

backend kubernetes-api-backend
  mode tcp
  balance roundrobin
  server master-1 10.0.0.11:6443 check
  server master-2 10.0.0.12:6443 check
  server master-3 10.0.0.13:6443 check

# Então, todos os clientes se conectam a 10.0.0.10:6443
# E o HAProxy roteia para o master disponível

Conclusão

Dominar a arquitetura do Kubernetes é fundamental para operar clusters em produção. Os três pontos principais que você deve levar para casa são:

  1. A dualidade Control Plane e Worker Nodes: O Control Plane é o "gerenciador" que toma decisões sobre o que deve rodar e como deve rodar, enquanto os Worker Nodes são os executores que realmente mantêm os containers funcionando. A comunicação entre eles segue um padrão declarativo onde você descreve o estado desejado.

  2. Reconciliation e resiliência contínua: O Kubernetes não é um sistema "fire and forget". Ele constantemente verifica se a realidade corresponde ao desejo declarado e corrige desvios. Se um Pod falha, ele é reiniciado. Se um nó morre, seus Pods são reagendados. Esta natureza auto-recuperável é o que torna o Kubernetes poderoso.

  3. Alta disponibilidade no design: De múltiplos nós de Control Plane ao etcd replicado e kubelet robusto, Kubernetes foi construído para tolerância a falhas. Compreender essas camadas de redundância permite que você construa sistemas realmente resilientes que continuam funcionando mesmo com falhas parciais.

Referências


Artigos relacionados