Saltar al contenido

Fundamentos de la orquestación de contenedores: de Docker a Kubernetes

Ejecutar un contenedor es fácil; orquestar cientos exige programación, redes, descubrimiento de servicios y autorrecuperación: eso es Kubernetes.

4 min de lectura
Diagrama de un clúster de Kubernetes mostrando pods, servicios y nodos

Ejecutar un contenedor en una sola máquina con docker run es sencillo. Pero las cargas de trabajo en producción requieren múltiples instancias en varios hosts, reinicios automáticos ante fallos, despliegues progresivos sin tiempo de inactividad y comunicación entre servicios. Las plataformas de orquestación de contenedores resuelven estos problemas. Kubernetes se ha convertido en el estándar de la industria, pero entender qué hace realmente —y por qué— importa más que memorizar YAML.

Los problemas que resuelve la orquestación

Sin orquestación, te conectas manualmente por SSH a los servidores, descargas imágenes, inicias contenedores, configuras la red y supervisas la salud. Cuando un contenedor muere, lo reinicias. Cuando el tráfico sube, añades contenedores. Cuando despliegas, detienes la versión antigua y arrancas la nueva —con tiempo de inactividad.

La orquestación automatiza todo esto:

ymlyaml
# A simple Kubernetes Deployment — declares desired state
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-server
spec:
  replicas: 3  # Always keep 3 instances running
  selector:
    matchLabels:
      app: api-server
  template:
    metadata:
      labels:
        app: api-server
    spec:
      containers:
        - name: api
          image: registry.example.com/api-server:v1.2.0
          ports:
            - containerPort: 3000
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "512Mi"
              cpu: "500m"

Declaras "quiero 3 réplicas de este contenedor" y Kubernetes garantiza que exactamente 3 estén ejecutándose en los nodos disponibles. Si un nodo cae, Kubernetes reprograma los pods en nodos saludables.

Conceptos fundamentales

Pods

Un Pod es la unidad desplegable más pequeña: uno o más contenedores que comparten red y almacenamiento. En la práctica, la mayoría de los pods contienen un único contenedor de aplicación.

ymlyaml
# Pod spec with liveness and readiness probes
spec:
  containers:
    - name: api
      image: registry.example.com/api-server:v1.2.0
      livenessProbe:
        httpGet:
          path: /health
          port: 3000
        initialDelaySeconds: 10
        periodSeconds: 15
      readinessProbe:
        httpGet:
          path: /ready
          port: 3000
        initialDelaySeconds: 5
        periodSeconds: 10

La liveness probe le indica a Kubernetes cuándo reiniciar un contenedor (está bloqueado o en un punto muerto). La readiness probe le indica a Kubernetes cuándo un contenedor puede aceptar tráfico (las dependencias están conectadas, el calentamiento ha terminado).

Servicios y redes

Los pods reciben direcciones IP efímeras que cambian en cada reinicio. Un Service proporciona un punto de acceso de red estable que enruta el tráfico hacia los pods saludables.

ymlyaml
# ❌ Hardcoding pod IPs — breaks on restart
# connection string: "http://10.0.4.23:3000"
 
# ✅ Using a Kubernetes Service — stable DNS name
apiVersion: v1
kind: Service
metadata:
  name: api-server
spec:
  selector:
    app: api-server  # Routes to pods with this label
  ports:
    - port: 80
      targetPort: 3000
  type: ClusterIP  # Internal only
 
# Other services connect via: http://api-server.default.svc.cluster.local
# Or simply: http://api-server (within the same namespace)

Despliegues progresivos

Cuando actualizas la imagen del contenedor, Kubernetes realiza por defecto una actualización progresiva (rolling update), reemplazando incrementalmente los pods antiguos por los nuevos.

ymlyaml
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1  # At most 1 pod down during update
      maxSurge: 1         # At most 1 extra pod during update

La secuencia del rollout para 3 réplicas:

  1. Crear 1 pod nuevo (v1.3.0) — ahora hay 3 antiguos + 1 nuevo
  2. Esperar a que el pod nuevo pase la readiness probe
  3. Terminar 1 pod antiguo (v1.2.0) — ahora hay 2 antiguos + 1 nuevo
  4. Repetir hasta que todos los pods ejecuten la v1.3.0
shbash
# Deploy a new version
kubectl set image deployment/api-server api=registry.example.com/api-server:v1.3.0
 
# Watch the rollout progress
kubectl rollout status deployment/api-server
 
# Something went wrong? Roll back instantly
kubectl rollout undo deployment/api-server

Gestión de la configuración

Kubernetes separa la configuración de las imágenes de contenedor mediante ConfigMaps y Secrets.

ymlyaml
# ConfigMap for non-sensitive configuration
apiVersion: v1
kind: ConfigMap
metadata:
  name: api-config
data:
  LOG_LEVEL: "info"
  CACHE_TTL: "300"
  MAX_CONNECTIONS: "100"
 
---
# Secret for sensitive data (base64 encoded, ideally with external secrets manager)
apiVersion: v1
kind: Secret
metadata:
  name: api-secrets
type: Opaque
data:
  DATABASE_URL: cG9zdGdyZXM6Ly91c2VyOnBhc3NAaG9zdDo1NDMyL2Ri
 
---
# Reference in the Deployment
spec:
  containers:
    - name: api
      envFrom:
        - configMapRef:
            name: api-config
        - secretRef:
            name: api-secrets

Límites y solicitudes de recursos

Sin restricciones de recursos, un contenedor que se comporta mal puede consumir toda la CPU y memoria de un nodo, afectando a todas las demás cargas de trabajo.

ymlyaml
# ❌ No resource constraints — risky in multi-tenant clusters
spec:
  containers:
    - name: api
      image: registry.example.com/api-server:v1.2.0
 
# ✅ Define requests (scheduling guarantee) and limits (hard cap)
spec:
  containers:
    - name: api
      image: registry.example.com/api-server:v1.2.0
      resources:
        requests:
          memory: "256Mi"   # Guaranteed minimum
          cpu: "250m"        # 0.25 CPU cores
        limits:
          memory: "512Mi"   # OOM-killed if exceeded
          cpu: "500m"        # Throttled if exceeded

Los requests determinan la programación: el scheduler coloca los pods en nodos con suficientes recursos disponibles. Los limits imponen topes estrictos: superar el límite de memoria mata el contenedor, superar el límite de CPU lo ralentiza (throttling).

Cuándo usar Kubernetes

Kubernetes añade una complejidad operativa considerable. Vale la pena cuando tienes muchos servicios que necesitan escalado independiente, despliegues automatizados y autorrecuperación. Para un solo servicio con poca complejidad, una plataforma más sencilla como Docker Compose, ECS o incluso un PaaS gestionado puede ser más apropiada.

Puntos clave

  1. La orquestación automatiza el despliegue, el escalado y la recuperación — tú declaras el estado deseado, la plataforma lo hace cumplir
  2. Los pods son la unidad atómica — usa liveness probes para la lógica de reinicio y readiness probes para el enrutamiento del tráfico
  3. Los Services proporcionan una red estable — nunca dependas directamente de las IPs de los pods
  4. Las actualizaciones progresivas permiten despliegues sin tiempo de inactividad — con capacidad de rollback instantáneo
  5. Define siempre requests y limits de recursos — evita los problemas de vecinos ruidosos en clústeres compartidos
  6. Kubernetes es una inversión — evalúa si tu complejidad operativa lo justifica antes de adoptarlo
Wilfredo Rujel

Wilfredo Rujel

Ingeniero de Software Full Stack

Compartir esta publicaciónX