From n00b to ZeroCool / Profesionalización

Kubernetes, el jefe final del cloud native (y cómo no morir en el intento)

Kubernetes sin humo: qué resuelve, conceptos clave y guía práctica para deploy, debug y operación. Tips reales para sobrevivir producción.

Lo que vale la pena leer aquí

Una noche cualquiera: ya se acabó el sprint, el release “era de puro config”, y de pronto el chat explota.

Una noche cualquiera: ya se acabó el sprint, el release “era de puro config”, y de pronto el chat explota.

—“Banda, el servicio no responde en production.”
—“Pero en mi máquina sí jalaba.”
—“¿Quién movió el Ingress?”

Abres la laptop ya guerrera (12% de batería porque el multicontacto del cowork murió), te conectas a la VPN que a veces sí y a veces no, y ahí está: Kubernetes.

El jefe final no porque sea “malo”, sino porque te obliga a jugar con mecánicas nuevas: declarativo, reconciliación, control loops, networking, permisos, recursos… y una cantidad ofensiva de YAML.

La neta: K8s te da superpoderes, pero te cobra en complejidad. Si lo adoptas por moda, se vuelve monstruo. Si lo entiendes con calma, es de lo más sólido para correr software serio sin vivir apagando fuegos.

Qué te vas a llevar

  • Qué problema resuelve Kubernetes (y cuándo ni lo voltees a ver).
  • Los conceptos que realmente necesitas para operar sin pánico: Pod, Deployment, Service, Ingress, ConfigMap/Secret, Namespace.
  • Una guía paso a paso para:
    • levantar un cluster local,
    • hacer deploy de un servicio,
    • exponerlo,
    • debuggear cuando truena,
    • y aplicar buenas prácticas de “producción básica”.
  • Errores comunes (de los que sí salen en el jale) y cómo salir en corto.

Por qué Kubernetes se siente como “jefe final”

Antes del cloud native, muchas personas vivimos el caminito clásico:

  1. “Sube el jar/php/node al server y reinicia.”
  2. “Ya somos 3 servers, hagamos un script.”
  3. “Ahora hay 10, usemos Ansible/Terraform.”
  4. “Metamos Docker para que no se rompa el setup.”
  5. “Y ahora… ¿cómo orquestamos 50 contenedores con autoscaling, rollouts y health checks?”

Ahí entra Kubernetes: un orquestador que mantiene tu estado deseado. Tú declaras “quiero 3 réplicas”, K8s se encarga de que existan; si una muere, la repone. No es magia: son controladores trabajando 24/7 para que el cluster se parezca a tu YAML.

¿Cuándo sí conviene?

  • Tienes varios servicios (o vas para allá) y quieres deploys repetibles.
  • Te importa el rolling update sin downtime.
  • Necesitas autoscaling (aunque sea básico por CPU/RAM).
  • Quieres estandarizar runtime y operación entre equipos sin reinventar la rueda.

¿Cuándo no?

  • Un solo servicio, tráfico estable, equipo chico, y el “tiempo de operar” vale oro.
  • No tienes CI/CD ni observabilidad: K8s no te la regala, te la exige.
  • Tu app depende de stateful pesado (DBs, colas, storage) y quieres “meterlo al cluster” nomás porque sí.

Decisión práctica: Kubernetes no es requisito para ser pro. Es una herramienta. Úsala cuando tu complejidad lo amerite, no cuando te lo pida un post de LinkedIn o el vendor.

Guía principal: tu primer deploy bien hecho (con debug de verdad)

La meta: correr un servicio web simple en Kubernetes, exponerlo y aprender a diagnosticarlo cuando algo se rompe (porque se va a romper).

1) Levanta un cluster local sin sufrir de gratis

Opciones decentes:

  • minikube (clásico, completo)
  • kind (Kubernetes in Docker, buenísimo para tests)
  • Docker Desktop Kubernetes (cómodo, pero a veces opaco)

Ejemplo con kind:

kind create cluster --name byteit
kubectl cluster-info
kubectl get nodes

Si kubectl no pega, casi siempre es contexto:

kubectl config get-contexts
kubectl config use-context kind-bytheit

Escena real: en oficina/escuela, el Wi‑Fi corporativo bloquea medio mundo o el proxy te mete zancadilla. Cluster local te salva para practicar sin depender de la red.

2) Crea un Namespace (porque production no es tu playground)

Evita tirar todo en default. Te ayuda a aislar, limpiar y controlar permisos.

kubectl create namespace demo
kubectl config set-context --current --namespace=demo

3) Deploy de una app (Deployment + Service)

Usaremos nginx para enfocarnos en Kubernetes. El workflow aplica igual para tu API.

Crea deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: "50m"
              memory: "64Mi"
            limits:
              cpu: "200m"
              memory: "128Mi"
          readinessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 3
            periodSeconds: 5
          livenessProbe:
            httpGet:
              path: /
              port: 80
            initialDelaySeconds: 10
            periodSeconds: 10

Crea service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: web-svc
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80

Aplica:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl get deploy,po,svc

Decisión práctica: requests/limits no son adorno. Sin requests, el scheduler adivina. Sin límites, un bug o un spike te puede tumbar el nodo y arrastrar a otros.

4) Acceso local (port-forward) para validar rápido

kubectl port-forward svc/web-svc 8080:80

Abre http://localhost:8080.

Tip de vida real: cuando estás atorado con IPs, DNS y firewalls de “levanta ticket y te contestan en 3 días”, port-forward es tu “déjame confirmar que sí corre” inmediato.

5) Debug básico cuando algo no levanta

Este combo te resuelve 80% de broncas:

kubectl get pods
kubectl describe pod <pod>
kubectl logs <pod>
kubectl logs <pod> -c <container>

Si el Pod no arranca:

  • ImagePullBackOff: imagen privada, tag inexistente, credenciales.
  • CrashLoopBackOff: tu app arranca y muere (config, env vars, puertos, migraciones).
  • Pending: no hay recursos, afinidad, taints, requests imposibles.

6) Configuración sin rebuild: ConfigMap y Secret

ConfigMap para config no sensible:

kubectl create configmap web-config --from-literal=APP_MODE=demo

Secret para cosas sensibles (ojo: en K8s base64 no es “encriptado”, es “codificado”):

kubectl create secret generic web-secret --from-literal=API_KEY="cambia-esto"

Móntalos como env vars (fragmento para tu Deployment):

env:
  - name: APP_MODE
    valueFrom:
      configMapKeyRef:
        name: web-config
        key: APP_MODE
  - name: API_KEY
    valueFrom:
      secretKeyRef:
        name: web-secret
        key: API_KEY

Tradeoff real: si tu organización trae compliance encima, tarde o temprano terminas en External Secrets + un vault (AWS Secrets Manager, GCP Secret Manager, Vault). Porque “Secret en etcd” puede ser suficiente… o un riesgo, según tu threat model.

7) Exponer hacia afuera: Ingress (cuando ya es “de verdad”)

En local puedes vivir con port-forward. En un cluster real vas a querer Ingress.

Primero necesitas un Ingress Controller (nginx, traefik, etc.). En kind/minikube es instalable; en managed K8s a veces ya viene como add‑on.

Ejemplo de Ingress (ingress.yaml):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
spec:
  rules:
    - host: web.local
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web-svc
                port:
                  number: 80

Tu DNS local puede ser /etc/hosts apuntando a la IP del ingress (en producción sería un LB + DNS real).

Decisión práctica: Ingress te da rutas y control, pero también mete complejidad (certificados, controllers, annotations). Si tu app es interna, a veces un Service ClusterIP + gateway interno es más simple y menos frágil.

Kubernetes, el jefe final del cloud native (y cómo no morir en el intento) - visual explicativa 1
Visual de apoyo: Qué te vas a llevar

Screenshots sugeridos (para que quede bien usable)

  • kubectl get pods -o wide mostrando estados (Running/Pending/CrashLoopBackOff).
  • Pantalla de kubectl describe pod con eventos (ImagePullBackOff, failed scheduling, probes failed).
  • kubectl get svc y el port-forward funcionando en el navegador.
  • YAML del Deployment con probes y resources resaltados.
  • Si usas Ingress: kubectl get ingress y el host resolviendo.

Errores comunes (los que sí te pasan en producción) + salida

1) “Mi Pod está Running pero no responde”

Causa típica: tu app escucha en 127.0.0.1 dentro del contenedor, no en 0.0.0.0.

  • Revisa el puerto:
    kubectl exec -it <pod> -- sh
    netstat -tulpn || ss -tulpn
    
  • Arreglo: configura tu server para bind 0.0.0.0.

2) Readiness/Liveness mal puestas y te autosaboteas

Si tu readinessProbe falla, el Service deja de mandarte tráfico (bien). Si tu livenessProbe falla, K8s te reinicia (también bien… hasta que te mete en un loop infernal).

Solución práctica:

  • Readiness: endpoint ligero, sin dependencias frágiles.
  • Liveness: más tolerante, con delays realistas.
  • Si tu app tarda en arrancar, usa startupProbe.

3) “Funcionaba ayer y hoy no”: tags latest y deploys no deterministas

Causa: la imagen cambió pero el tag no. Kubernetes cree que ya la tiene.

Solución:

  • Usa tags inmutables (1.2.3 o mejor digest sha256).
  • En CI, publica imagen con SHA del commit.

4) Te quedas sin recursos y el scheduler te manda a la banca (Pending)

Revisa:

kubectl describe pod <pod> | sed -n '/Events/,$p'

Solución:

  • Ajusta requests a algo realista.
  • Si tu cluster es chico, acepta la realidad: necesitas más nodos o menos hambre.

5) “No puedo hacer kubectl, me marca forbidden”

Bienvenido a RBAC.

Solución:

  • Confirma tu identidad/contexto.
  • Pide/crea un Role/ClusterRole correcto.
  • No uses cluster-admin como curita permanente; es deuda técnica con intereses.

Escena muy de jale: el admin se fue de vacaciones, tú entras a cubrir, y te dicen “pues súbele permisos mientras”. Se siente tentador. No lo hagas sin dejar evidencia y sin plan de rollback. Luego llega auditoría… o un incidente.

Kubernetes, el jefe final del cloud native (y cómo no morir en el intento) - visual explicativa 2
Visual de apoyo: Por qué Kubernetes se siente como “jefe final”

Checklist final (para sentirte más pro y menos improvisado)

  • Tengo Namespaces por ambiente/equipo (y no todo vive en default).
  • Mis Deployments tienen readinessProbe y livenessProbe (y no están agresivas).
  • Definí requests y limits (y los medí en staging).
  • Uso tags inmutables para imágenes (nada de latest en producción).
  • Mis configs están en ConfigMap/Secret o un gestor externo (con rotación si aplica).
  • Sé dónde ver logs (kubectl logs) y eventos (kubectl describe).
  • Tengo una ruta de rollback (Deployment rollout o GitOps).
  • Tengo al menos métricas básicas (CPU/RAM, latencia, errores) antes de “escalarlo”.

FAQ

1) ¿Kubernetes es lo mismo que Docker?

No. Docker (o containerd) corre contenedores; Kubernetes los orquesta: scheduling, self‑healing, rollouts, networking, config, scaling.

2) ¿Necesito Kubernetes para ser cloud-native?

No necesariamente. Puedes armar un stack cloud-native con contenedores + CI/CD + observabilidad en una plataforma más simple. Kubernetes entra cuando la operación/escala lo justifica.

3) ¿Qué aprendo primero: Helm o YAML a mano?

Primero YAML a mano para entender qué estás aplicando. Luego Helm para empaquetar y versionar despliegues sin volverte loco copiando manifests.

4) ¿Qué es lo mínimo para que un cluster sea “operable” en producción?

Monitoreo (métricas), logging centralizado, backups si hay state, control de accesos (RBAC), y un proceso de deploy/rollback repetible. Sin eso, estás apostando.

5) ¿Cómo empiezo a debuggear sin perderme?

Orden rápido: kubectl get podsdescribe (eventos) → logsexec si necesitas asomarte. Y siempre verifica: imagen, env vars, puertos, probes y recursos.

Siguiente episodio

Cuando Kubernetes ya está corriendo, el siguiente monstruo es poder verlo: métricas, logs y trazas sin sentir que estás leyendo la Matrix.

Nos vamos a meter con observabilidad cloud-native para que los incidentes duren minutos, no toda la noche.