Kubernetes para Quem Já Trabalha com Docker
Kubernetes para Quem Já Trabalha com Docker
Introdução
Se você domina docker run, docker compose e já imaginou escalar seus serviços sem tocar em scripts de supervisord, chegou o momento certo. Kubernetes (ou K8s) é a evolução natural do Docker para ambientes produtivos: orquestação declarativa, self-healing e scaling automático. No entanto, muitos dos conceitos são novos. Este artigo traduz sua experiência com Docker para o universo Kubernetes, com YAMLs completos, explicações de control plane e laboratórios práticos. Ao final, você será capaz de:
– Compreender a diferença entre Docker (executar) e Kubernetes (declarar).
– Instalar um cluster single-node usando kind ou minikube.
– Criar Deployments, Services, Ingress, ConfigMap, Secret e PVC.
– Diagnóstico de problemas comuns com kubectl.
– Entender a segurança e boas práticas de produção.
O que você vai aprender
- Arquitetura do cluster Kubernetes.
- Workload Resources:
Pod,Deployment,Service,Ingress. - Config Management:
ConfigMapeSecret. - Persistência:
PersistentVolumeeStorageClass. - Diagnóstico e troubleshooting com
kubectl.
Pré-requisitos
- Docker instalado e funcionando (não será necessário
docker run, apenas como backend). - Conexão à internet para baixar imagens do
kindouminikube. - Conhecimento básico de Linux e YAML.
Conceitos fundamentais
| Conceito | Definição | Relação com Docker |
|---|---|---|
| Pod | Unidade mínima de execução – um ou containers co-locados. | Um Pod é um wrapper ao redor de um ou mais containers. |
| Deployment | Declarativo: desejo N réplicas, atualizações em rolling update. | Substitui docker run -d + restart: always. |
| Service | Abstraction de rede – ClusterIP, NodePort, LoadBalancer. | Equivalente a expor porta via docker -p, mas sem IP fixo. |
| Ingress | Roteamento HTTP baseado em host/path para Services. | Substitui proxy reverso (NGINX) manual. |
| Namespace | Isolamento lógico – múltiplos ambientes em um cluster. | Não existe equivalente direto no Docker. |
| ConfigMap/Secret | Variáveis de ambiente e arquivos de configuração. | Substituem -e VAR=value ou volume de arquivos. |
| PVC/StorageClass | Persistência de dados independente do Pod. | Similar a volume bind mount, mas com provisionamento automático. |
| Control Plane | Componentes que gerenciam o estado desejado. | Nenhum equivalente – k8s faz o trabalho de orquestrador. |
O que Kubernetes resolve (e o que NÃO resolve)
Resolve:
– Escalabilidade automática de réplicas.
– Self-healing (recria Pods mortos).
– Rolling updates sem downtime.
– Balanceamento de carga interno/externo.
– Gerenciamento de credensias e configurações.
NÃO resolve:
– Orquestração de hosts (precisa de cluster).
– Configuração de rede avançada (CNI ainda é plugin).
– Builds de imagens (use docker build ou CI/CD).
Diferenças para Docker
| Aspecto | Docker | Kubernetes |
|---|---|---|
| Modelo | Imperativo (execute este container) | Declarativo (o estado desejado é este YAML) |
| Escopo | Um host | Múltiplos hosts (cluster) |
| Escalabilidade | Manual (docker-compose scale) ou script |
Automática (replicas: 3) |
| Atualização | docker stop && docker run |
kubectl rollout restart com novo YAML |
| Degradação | Falha total se processo morre | restartPolicy: Always no Pod |
Preparação do ambiente
- Verificar versão do Docker –
docker --version≥ 24.x. - Instalar
kind– usado para criar clusters locais rápidos. - Configurar
kubectl– CLI oficial para comunicação com o cluster. - Criar namespace de testes –
dev,stagingeprod.
Tutorial passo a passo
1. Instalar o cluster local com Kind
Objetivo: Criar um cluster Kubernetes em containers Docker.
# Instalar kind (v0.20.0)
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-$(uname)-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
# Criar cluster com 2 nodes (1 control-plane, 1 worker)
cat <<EOF > kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
EOF
kind create cluster --name dev-cluster --config kind-config.yaml
# Verificar
kubectl cluster-info --context kind-dev-cluster
Explicação: kind usa containers Docker como nodes. O control-plane roda dentro de um pod; o worker também. O kubeconfig é ajustado automaticamente.
Resultado esperado: kubectl get nodes retorna 2 nós com status Ready.
2. Instalar o Ingress Controller (NGINX)
Objetivo: Habilitar rotas HTTP externas.
# Usar helm para instalar
curl -fsSL -o /tmp/helm https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 /tmp/helm
/tmp/helm install ingress-nginx ingress-nginx/ingress-nginx --namespace ingress-nginx --create-namespace --set controller.publishService.enabled=true
# Aguardar pods prontos
kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=90s
Explicação: O Helm simplifica a instalação. O controller deixa de ouvir na porta 80/443 do node.
Resultado esperado: kubectl get svc -n ingress-nginx mostra ingress-nginx-controller com EXTERNAL-IP = localhost.
3. Criar um Deployment básico
Objetivo: Implantar 2 réplicas de um app Nginx customizado.
# app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
labels:
app: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "250m"
memory: "256Mi"
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: web-app-svc
spec:
type: NodePort
selector:
app: web-app
ports:
- protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
kubectl apply -f app-deployment.yaml
kubectl get pods -l app=web-app
Explicação: Deployment gere 2 pods. Service tipo NodePort expõe na porta 30080 de cada node.
Resultado esperado: Pods com READY=1/1, Service escutando em 30080.
4. Configurar ConfigMap e Secret
Objetivo: Passar variáveis e credenciais de forma segura.
# app-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: web-config
data:
ENVIRONMENT: "production"
LOG_LEVEL: "info"
---
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
stringData:
username: "admin"
password: "SuperSecret123"
kubectl apply -f app-config.yaml
# Montar como env
kubectl set env deployment/web-app --from=configmap/web-config --from=secret=db-credentials
Explicação: ConfigMap para valores não sensíveis, Secret (stringData base64) para credenciais. Ambos podem ser injetados como env ou arquivos via volume.
Resultado esperado: kubectl exec <pod> -- env | grep ENVIRONMENT exibe production.
5. Criar PVC e StorageClass
Objetivo: Persistir dados do container.
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: webapp-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
# Usar storageClass local do kind
kubectl apply -f pvc.yaml
# Verificar PVC bound
kubectl get pvc
Explicação: accessModes: ReadWriteOnce permite escrita pelo pod. O kind cria um local-path StorageClass automaticamente.
Resultado esperado: PVC com status Bound a um PV.
6. Criar Ingress com roteamento
Objetivo: Acessar a aplicação via hostname.
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: web-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: dev.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: web-app-svc
port:
number: 80
# Adicionar ao /etc/hosts
echo "127.0.0.1 dev.local" | sudo tee -a /etc/hosts
kubectl apply -f ingress.yaml
# Testar
curl -H "Host: dev.local" http://localhost
Explicação: O Ingress roteia requisições com Host: dev.local para o Service web-app-svc.
Resultado esperado: Resposta HTTP 200 com conteúdo do Nginx padrão.
7. Simular Rolling Update e rollback
Objetivo: Atualizar a imagem sem downtime.
# Atualizar
kubectl set image deployment/web-app nginx=nginx:1.25.3
# Ver rollout status
kubectl rollout status deployment/web-app
# Se necessário, rollback
kubectl rollout undo deployment/web-app
Explicação: Kubernetes mantém 25% das réplicas antigas durante o update, garantindo disponibilidade.
Resultado esperado: Histórico de revisões visível em kubectl rollout history.
Laboratório
Cenário: Deploy de um app customizado com ConfigMap, Secret, PVC e Ingress sobre cluster Kind.
Passos do laboratório
- Crie o cluster
kind create cluster --name lab --config kind-config.yaml. - Clone o repositório de exemplo:
git clone https://github.com/bittux/lab-kubernetes-demo.git
cd lab-kubernetes-demo
- Ajuste o ConfigMap para variação de host:
# host-vars.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
SITE_NAME: "Meu Laboratório K8s"
VERSION: "1.0.0"
- Aplique todos os recursos:
kubectl create namespace lab
kubectl apply -n lab -f k8s/
- Valide:
kubectl get all -n lab
kubectl describe ingress -n lab
- Acesse via
http://localhostcom Hostlab.local.
# Troubleshooting: problemas comuns e como resolver
Sintoma 1 – ImagePullBackOff
- Possível causa: Nome da imagem errado, tag não existe ou registro não autenticado.
- Diagnóstico:
kubectl describe pod <pod>→ “Failed to pull image”. - Solução: Verifique a tag (
docker pull nginx:1.25-alpine); criedocker-registrySecret e referencie emimagePullSecrets. - Prevenção: Use tags estáveis como
nginx:v1.25e teste localmente antes de subir ao cluster.
Sintoma 2 – CrashLoopBackOff
- Possível causa: Falha no início do container (erro de configuração, falta de permissões).
- Diagnóstico:
kubectl logs <pod>;kubectl describe pod <pod>. - Solução: Corrija o comando de entrada (
commandouentrypoint), ajuste permissões de arquivo (chmod), adicionesecurityContext. - Prevenção: Use
restartPolicy: Neverem Jobs de migração, adicionepostStartliveness probe.
Sintoma 3 – Pending Pod (scheduling de resources)
- Possível causa: Nenhum node disponível com recursos suficientes.
- Diagnóstico:
kubectl describe pod <pod>→ evento “0/1 nodes are available: 1 Insufficient cpu.”`. - Solução: Reduza
requests, adicione node ao cluster (kind create cluster --name extended --nodes 3). - Prevenção: Monitore uso de recursos com
kubectl top nodese ajusterequests/limitsem conjunto.
Sintoma 4 – ContainerCreating (volume provisioning)
- Possível causa: Provisionador de storage não está disponível ou StorageClass errado.
- Diagnóstico:
kubectl describe pvc <pvc>. - Solução: Use StorageClass correto (
local-pathno Kind) ou configure driver CSI adequado. - Prevenção: Verifique se o provisionador está rodando (
kubectl get pods -n kube-system).
Sintoma 5 – Readiness probe failing
- Possível causa: Probe apontando para porta ou path errado.
- Diagnóstico:
kubectl describe pod <pod>→ “Readiness probe failed”. - Solução: Ajuste
initialDelaySecondseperiodSeconds; verifique se a aplicação responde ao path/healthz. - Prevenção: Adicione endpoint de saúde na aplicação e teste localmente.
# Segurança
- RBAC: Atribua papéis mínimos (
Role,RoleBinding). Evitecluster-adminem produção. - Namespaces: Isolar ambientes (dev, staging, prod) impede vazamento de credenciais.
- Secrets: Não armazene no Git. Use
sealed-secretsou externas (AWS Secrets Manager). - Network Policies: Defina
NetworkPolicypara restringir tráfego entre Pods. - Images: Use imagens oficiais ou construa via CI com scan de vulnerabilidades (Trivy, Grype).
- Resource Limits: Defina
requestselimitspara evitar que um Pod monopolize recursos.
# Boas práticas
- Nunca crie Pods soltos em produção – sempre use
Deployment,StatefulSetouDaemonSet. - Versione manifests – use Git com
kustomizeouhelmpara ambientes. - Labels e Anotações – padronize labels (
app,tier,environment) para facilitar busca. - Health Checks – sempre adicione
livenessProbeereadinessProbe. - Horizontal Pod Autoscaler (HPA) – configure baseado em CPU ou métricas custom
metrics-server. - Rolling Update – ajuste
maxSurge: 25%,maxUnavailable: 25%conforme SLA. - Service Discovery – use
ClusterIPpara comunicação interna;LoadBalancerapenas quando preciso (custo de nuvem).
Comparação de ferramentas
| Ferramenta | Uso | Vantagem | Desvantagem |
|---|---|---|---|
| Docker Compose | Ambiente local, desenvolvimento | Simples, rápido | Não escala, sem HA |
| Kind | Testes locais, CI | Rápido, Docker-based | Não produzido, sem rede real |
| Minikube | Desenvolvimento | Plugins (ingress, dashboard) | Mais lento que Kind |
| k3s | Edge/IoT, produção leve | Tudo em um binário | Menos recursos avançados |
| Kops / EKS / GKE / AKS | Produção em nuvem | Gerenciado, HA | Custo, lock-in de provedor |
Conclusão
Kubernetes não substitui Docker – ele o orquestra. Com o conhecimento de Docker, você entende containers, imagens e rede. Em Kubernetes, essas ideias se transformam em Pods, Deployments e Services. Ao seguir os passos acima, você tem um laboratório funcional para experimentar upgrades, rollbacks e novas funcionalidades. Em produção, combine k8s com CI/CD (GitHub Actions, ArgoCD) e ferramentas de observação (Prometheus, Grafana) – como veremos no artigo 10 monitoramento zabbix prometheus grafana.
Perguntas frequentes
Q: Posso usar Docker Compose para migrar para Kubernetes?
A: Sim, com kompose – converte docker-compose.yml para manifests K8s. Não é perfeito, mas acelera o onboarding.
Q: Qual a diferença entre Deployment e StatefulSet?
A: Deployment para apps stateless; StatefulSet para stateful (banco, redis). Garante identidade de Pod e ordenação.
Q: Como backup o cluster Kubernetes?
A: Otimize etcd com etcdctl para clusters management plane. Para workloads, use velero (backup de recursos e PV).
Próximo passo
Agora que você domina Kubernetes Para Quem Ja Trabalha Com Docker, o próximo passo lógico da nossa trilha de aprendizado é continuar desenvolvendo suas habilidades.
→ Continue: Ansible na Prática
Artigos relacionados
Estes artigos complementam o conteúdo apresentado:
