DevOps
Kubernetes para Devs: Os Conceitos que Você Precisa Entender
12 de setembro de 2024·Paulo de Paula
Kubernetes (K8s) é complexo quando você tenta aprender tudo de uma vez. Aprenda por camadas: primeiro entenda o problema que cada recurso resolve, depois a sintaxe.
Pod vs Container
Um Pod é a menor unidade deployável do K8s — não o container. Um Pod pode conter múltiplos containers que compartilham rede e storage.
# Pod simples (nunca crie Pods diretamente em produção — use Deployment)
apiVersion: v1
kind: Pod
metadata:
name: minha-api
spec:
containers:
- name: api
image: minha-api:1.0.0
ports:
- containerPort: 3000
- name: log-sidecar # container auxiliar no mesmo Pod
image: fluentd:latest
# compartilha network namespace com o container apiPor que Pods e não containers diretos? O sidecar pattern (log collector, service mesh proxy) e o init container pattern dependem dessa abstração.
Deployment com rolling update
apiVersion: apps/v1
kind: Deployment
metadata:
name: minha-api
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: minha-api
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # máximo de Pods extras durante update
maxUnavailable: 0 # zero downtime: nunca remove antes de adicionar
template:
metadata:
labels:
app: minha-api
spec:
containers:
- name: api
image: minha-api:1.2.3
ports:
- containerPort: 3000
resources:
requests: # K8s usa para scheduling
cpu: "250m" # 250 millicores = 0.25 vCPU
memory: "256Mi"
limits: # K8s aplica como teto
cpu: "500m" # CPU throttled se exceder
memory: "512Mi" # Pod reiniciado (OOMKilled) se exceder
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 15
periodSeconds: 20Diferença crítica entre requests e limits:
requests: garante que o Pod terá esses recursos. Usado pelo scheduler para decidir em qual node colocar o Pod.limits.cpu: CPU é throttled (não mata o Pod).limits.memory: Se exceder, o Pod é morto com OOMKilled. Defina um limite realista.
Services: expondo Pods
# ClusterIP — padrão, acesso apenas dentro do cluster
apiVersion: v1
kind: Service
metadata:
name: minha-api
spec:
selector:
app: minha-api # aponta para Pods com esse label
ports:
- port: 80 # porta do Service
targetPort: 3000 # porta do container
type: ClusterIP
---
# LoadBalancer — cria um load balancer externo (AWS ALB, GCP LB, etc.)
spec:
type: LoadBalancer
---
# NodePort — expõe em porta fixa de cada node (desenvolvimento/testes)
spec:
type: NodePort
ports:
- port: 80
targetPort: 3000
nodePort: 30080 # 30000-32767ConfigMap e Secret
# ConfigMap para configurações não-sensíveis
apiVersion: v1
kind: ConfigMap
metadata:
name: api-config
data:
NODE_ENV: "production"
LOG_LEVEL: "info"
API_TIMEOUT: "30000"
---
# Secret para dados sensíveis (base64 encoded)
apiVersion: v1
kind: Secret
metadata:
name: api-secrets
type: Opaque
data:
DATABASE_URL: cG9zdGdyZXM6Ly8uLi4= # base64 de "postgres://..."
JWT_SECRET: c2VjcmV0LWtleQ==Usando no Deployment:
spec:
containers:
- name: api
envFrom:
- configMapRef:
name: api-config
- secretRef:
name: api-secrets
# Ou variáveis individuais:
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: api-secrets
key: DATABASE_URLHorizontal Pod Autoscaler
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: minha-api-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: minha-api
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # escala quando CPU > 70%
- type: Resource
resource:
name: memory
target:
type: AverageValue
averageValue: 400MiIngress com TLS
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api-ingress
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rate-limit: "100"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.meusite.com.br
secretName: api-tls-cert # cert-manager preenche automaticamente
rules:
- host: api.meusite.com.br
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: minha-api
port:
number: 80kubectl: comandos do dia a dia
# Ver recursos
kubectl get pods -n production
kubectl get pods -n production -w # watch em tempo real
kubectl describe pod minha-api-abc123 -n production
# Logs
kubectl logs minha-api-abc123 -n production
kubectl logs -f deployment/minha-api -n production # follow
kubectl logs --previous minha-api-abc123 # último crash
# Executar comando no container
kubectl exec -it minha-api-abc123 -n production -- sh
# Port-forward para acessar localmente
kubectl port-forward svc/minha-api 8080:80 -n production
# Aplicar/deletar manifests
kubectl apply -f k8s/
kubectl delete -f k8s/deployment.yaml
# Rollback
kubectl rollout undo deployment/minha-api -n production
kubectl rollout history deployment/minha-api -n production
kubectl rollout status deployment/minha-api -n productionO melhor caminho para aprender K8s em produção: comece com um namespace de staging, pratique rollouts e rollbacks, e estude os logs quando algo der errado — o kubectl describe é seu melhor amigo.