1. O problema que o Kubernetes resolve
Rodar um container isolado, à mão, com docker run, resolve bem o problema de empacotar e distribuir uma aplicação. Mas assim que essa aplicação precisa rodar em produção — com múltiplas réplicas, tolerância a falhas, atualizações sem downtime e escalando conforme a demanda — o "container solto" vira um problema de gestão manual: quem reinicia um container que caiu? Quem distribui a carga entre várias instâncias? Quem decide em qual máquina cada container roda quando há dezenas de servidores disponíveis? Scripts caseiros de docker run e cron para verificar se o processo ainda está vivo resolvem por um tempo, mas não escalam além de poucos serviços.
O Kubernetes (às vezes abreviado como k8s) é um orquestrador de containers: um sistema que recebe uma descrição de "o que" deve estar rodando (quantas réplicas, quanto de CPU/memória, quais portas expor) e se encarrega do "como" — decide em qual máquina cada container roda, reinicia o que falhar, distribui tráfego entre réplicas saudáveis e reagenda containers automaticamente se um servidor inteiro cair. Esta é a primeira parte de uma série que vai do zero ao avançado em Kubernetes e GitOps: hoje o foco é entender o problema que o Kubernetes resolve e os conceitos iniciais que sustentam tudo o que vem depois.
2. Containers soltos e VMs vs orquestração
Comparado a rodar containers "soltos" (um docker run por servidor, gerenciado manualmente ou por scripts), o Kubernetes automatiza justamente o que se torna inviável de fazer à mão em escala:
- Auto-recuperação (self-healing): se um container trava ou o processo morre, o Kubernetes detecta e sobe um novo automaticamente — sem intervenção humana e, idealmente, sem impacto perceptível para quem usa a aplicação.
- Escalonamento: aumentar de 2 para 10 réplicas de uma aplicação é uma mudança de configuração (ou automática, via métricas de uso), não um processo manual de logar em servidores e rodar comandos um por um.
-
Distribuição de carga: o Kubernetes decide em qual máquina (
node) cada container roda, considerando recursos disponíveis, e distribui tráfego entre as réplicas saudáveis de um serviço automaticamente. - Atualizações sem downtime: trocar a versão de uma aplicação pode ser feito substituindo réplicas gradualmente (rolling update), mantendo o serviço no ar durante todo o processo.
Comparado a máquinas virtuais geridas manualmente (uma aplicação por VM, escalada criando mais VMs), o ganho é semelhante ao que containers já trazem sobre VMs isoladamente: densidade muito maior (várias aplicações compartilhando os mesmos servidores físicos com isolamento adequado) e inicialização em segundos em vez de minutos — mas agora com um sistema que decide automaticamente onde cada carga roda, em vez de alguém escolher manualmente em qual VM cada aplicação vai.
Isso não significa que toda aplicação precisa de Kubernetes — um sistema pequeno, com um ou dois serviços e baixa necessidade de escala, pode viver tranquilamente com docker run bem configurado ou Docker Compose (veja a série sobre Docker deste blog). O Kubernetes compensa o esforço quando a quantidade de serviços, a necessidade de alta disponibilidade ou a variação de carga tornam a gestão manual inviável.
3. Conceitos fundamentais: Pods, Deployments e Services
O Kubernetes organiza tudo em torno de objetos descritos declarativamente (normalmente em YAML), que dizem ao cluster o estado desejado. Três deles aparecem em praticamente toda aplicação:
- Pod: a menor unidade que o Kubernetes gerencia diretamente. Um Pod contém um ou mais containers que compartilham rede e armazenamento — na prática, a grande maioria dos Pods tem exatamente um container, com containers adicionais reservados para casos específicos (como um "sidecar" que coleta logs). Pods são efêmeros: quando um Pod morre, ele não é "recriado" no sentido de reviver o mesmo Pod — um novo Pod é criado do zero em seu lugar.
- Deployment: descreve quantas réplicas de um Pod devem existir e como atualizá-las. É o Deployment que garante que, se um Pod morrer, outro toma seu lugar automaticamente, e que gerencia rolling updates ao trocar a versão de uma imagem.
-
Service: como Pods são efêmeros e ganham um IP novo cada vez que são recriados, não é possível apontar diretamente para o IP de um Pod de forma confiável. Um Service resolve isso expondo um endereço estável (nome DNS interno e IP fixo dentro do cluster) que distribui tráfego entre todos os Pods saudáveis que casam com um determinado rótulo (
label) — independentemente de quantos Pods existem ou de terem sido recriados.
Deployment "api"
├── garante 3 réplicas do Pod
├── Pod (réplica 1) ── container: api:1.2
├── Pod (réplica 2) ── container: api:1.2
└── Pod (réplica 3) ── container: api:1.2
Service "api" (IP estável, DNS interno "api")
└── distribui tráfego entre as 3 réplicas do Pod acima
Essa relação — Deployment garantindo réplicas de Pods, Service expondo um endereço estável para eles — é o alicerce sobre o qual praticamente todo o resto do Kubernetes (ConfigMaps, Secrets, Ingress, volumes, e os conceitos de GitOps discutidos mais adiante nesta série) se apoia.
4. Experimentando localmente com Minikube ou Kind
Não é preciso um cluster de produção para começar a aprender Kubernetes. Duas ferramentas populares criam um cluster completo rodando localmente, dentro do Docker ou de uma VM leve:
# Minikube — cria um cluster local em uma VM/container
minikube start
# Kind (Kubernetes in Docker) — cria o cluster inteiro dentro de containers Docker
kind create cluster
Ambas resultam em um cluster funcional acessível pelo kubectl (a CLI oficial do Kubernetes, assunto completo do próximo artigo desta série). Para confirmar que o cluster está de pé:
kubectl cluster-info
kubectl get nodes
O segundo comando lista os nodes (máquinas, reais ou virtuais, que compõem o cluster) — em um cluster local, normalmente apenas um node fazendo o papel de servidor e worker ao mesmo tempo.
5. Um primeiro deploy na prática
Com o cluster local de pé, um Deployment mínimo já ilustra os três conceitos vistos acima. Em um arquivo nginx-deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
Aplicando ao cluster:
kubectl apply -f nginx-deployment.yaml
kubectl get pods
kubectl get deployments
kubectl get services
O primeiro comando (kubectl apply) é a forma declarativa de trabalhar com Kubernetes: em vez de dizer passo a passo o que fazer, descreve-se o estado desejado (três réplicas do Nginx, expostas por um Service) e o Kubernetes se encarrega de fazer a realidade convergir para essa descrição — criando os três Pods, e mantendo-os assim mesmo que algum caia. Esse modelo declarativo, aplicado a partir de arquivos versionados em um repositório Git, é exatamente a ideia que a série vai aprofundar no Artigo 3, ao introduzir GitOps.
6. Conclusão e próximos passos
Nesta primeira parte, vimos o problema real que o Kubernetes resolve — orquestrar containers em escala, algo inviável de gerenciar manualmente —, como ele se compara a containers soltos e VMs geridas manualmente, os três conceitos que sustentam qualquer aplicação no cluster (Pods, Deployments e Services) e subimos um primeiro Deployment de ponta a ponta em um cluster local. No próximo artigo, o foco vai para o kubectl no dia a dia: comandos essenciais, organização de recursos com namespaces, ConfigMaps e Secrets, e os primeiros deploys de aplicações reais.
Imagem de capa: Logo oficial do Kubernetes — repositório kubernetes/kubernetes
Referências:
Top comments (0)