Saltar para o conteúdo
Kubernetes para Devs: Os Conceitos que Você Precisa Entender
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 api

Por 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: 20

Diferenç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-32767

ConfigMap 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_URL

Horizontal 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: 400Mi

Ingress 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: 80

kubectl: 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 production

O 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.