Docker y Kubernetes no son competidores: Docker crea y ejecuta contenedores, Kubernetes los orquesta en producción. Entender cuándo necesitas uno, otro, o ambos, es fundamental para cualquier ingeniero DevOps.

Docker y Kubernetes: Conceptos Diferentes

La pregunta “Docker vs Kubernetes” parte de una confusión habitual. No es una elección entre uno u otro en la mayoría de los casos. Son herramientas que operan en capas distintas:

  • Docker es una plataforma para crear, empaquetar y ejecutar contenedores
  • Kubernetes es un sistema para orquestar, escalar y gestionar contenedores en producción

Es como comparar un motor con un sistema de gestión de flotas. El motor (Docker) hace que el vehículo funcione. El sistema de flotas (Kubernetes) coordina cientos de vehículos.

Qué es Docker

Docker es la plataforma que popularizó los contenedores. Permite empaquetar una aplicación junto con todas sus dependencias en una imagen portable que se ejecuta de forma idéntica en cualquier máquina.

Componentes de Docker

ComponenteFunción
Docker EngineRuntime que ejecuta contenedores
DockerfileReceta para construir imágenes
Docker ImagePaquete inmutable con app + dependencias
Docker ContainerInstancia en ejecución de una imagen
Docker HubRegistro público de imágenes
Docker ComposeOrquestación local multi-contenedor

Ejemplo: Dockerizar una Aplicación

# Dockerfile multi-stage para app Node.js
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

FROM node:20-alpine
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -qO- http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]
# Construir y ejecutar
docker build -t mi-app:1.0 .
docker run -d -p 3000:3000 --name mi-app mi-app:1.0

Docker Compose para Desarrollo Local

Docker Compose permite definir aplicaciones multi-contenedor en un solo archivo:

# docker-compose.yml
services:
  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 5s
      timeout: 3s
      retries: 5

  cache:
    image: redis:7-alpine
    volumes:
      - redisdata:/data

volumes:
  pgdata:
  redisdata:

Qué es Kubernetes

Kubernetes (K8s) es un sistema de orquestación de contenedores creado por Google y donado a la CNCF. Gestiona el despliegue, escalado, networking y disponibilidad de aplicaciones containerizadas en clusters de servidores.

Problemas que Kubernetes Resuelve

Cuando tienes una aplicación en producción con múltiples contenedores, necesitas responder preguntas como:

  • Si un contenedor muere, ¿quién lo reinicia?
  • Si hay más tráfico, ¿quién crea más instancias?
  • ¿Cómo distribuyo tráfico entre múltiples instancias?
  • ¿Cómo actualizo sin downtime?
  • ¿Cómo gestiono secretos y configuración?
  • ¿Cómo manejo el almacenamiento persistente?

Kubernetes responde todas estas preguntas.

Componentes de Kubernetes

ComponenteFunción
PodUnidad mínima de despliegue (1+ contenedores)
DeploymentGestiona réplicas de pods y rolling updates
ServiceExpone pods con IP estable y load balancing
IngressEnrutamiento HTTP/HTTPS externo
ConfigMap/SecretConfiguración y secretos externalizados
NamespaceAislamiento lógico de recursos
HPAAutoescalado basado en métricas
PersistentVolumeAlmacenamiento persistente

Ejemplo: Desplegar en Kubernetes

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mi-app
  labels:
    app: mi-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mi-app
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: mi-app
    spec:
      containers:
      - name: mi-app
        image: mi-registro/mi-app:1.0
        ports:
        - containerPort: 3000
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 10
          periodSeconds: 15
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: url
---
apiVersion: v1
kind: Service
metadata:
  name: mi-app-service
spec:
  selector:
    app: mi-app
  ports:
  - port: 80
    targetPort: 3000
  type: ClusterIP
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: mi-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: mi-app
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70

Comparación Directa

Funcionalidad

CapacidadDocker (solo)Docker + ComposeKubernetes
Crear contenedoresSiSiNo (usa containerd/CRI-O)
Multi-contenedor localManualSiOverkill
Auto-healingNoNoSi
AutoescaladoNoNoSi (HPA/VPA/KEDA)
Load balancingNoLimitadoSi (Services + Ingress)
Rolling updatesNoLimitadoSi (nativo)
Service discoveryNoDNS internoDNS + Services
Gestión de secretosNoVariables de entornoSi (Secrets + external-secrets)
Multi-nodoNoNoSi (diseñado para clusters)
Storage persistenteVolumes localesVolumes localesPV/PVC + CSI drivers

Complejidad

AspectoDockerKubernetes
Curva de aprendizajeBaja (horas/días)Alta (semanas/meses)
Configuración inicialUn comandoCluster completo
Operación día a díaSimpleRequiere expertise
DebuggingDirectoMúltiples capas
Costo operativoBajoAlto (cluster + operadores)

Costos en Cloud

EscenarioDocker (ECS Fargate)Kubernetes (EKS)
Costo base del servicio$0~$73/mes por cluster
3 servicios pequeños~$30-50/mes~$150-200/mes
10 servicios medianos~$200-400/mes~$400-600/mes
50+ microservicios~$1,000-3,000/mes~$1,500-4,000/mes
Equipo necesario1-2 DevOps2-4 DevOps/SRE

Cuándo Usar Solo Docker

Docker sin Kubernetes es suficiente cuando:

  • Aplicaciones simples: Un monolito o pocos servicios
  • Desarrollo local: Docker Compose para simular el entorno de producción
  • Equipos pequeños: 1-5 desarrolladores sin equipo de infraestructura dedicado
  • Tráfico predecible: Sin necesidad de autoescalado agresivo
  • Presupuesto limitado: No puedes justificar el costo de operar un cluster K8s
  • Servicios managed: Usar ECS Fargate, Cloud Run o Azure Container Instances

Ejemplo Real: Startup con 3 Microservicios

Arquitectura:
  API Gateway → Auth Service → Product Service → PostgreSQL

Infraestructura:
  AWS ECS Fargate (sin servidores que gestionar)
  ALB para load balancing
  RDS PostgreSQL managed

Costo mensual: ~$150-200
Equipo necesario: 1 DevOps part-time

Cuándo Necesitas Kubernetes

Kubernetes se justifica cuando:

  • Muchos microservicios: 10+ servicios que necesitan coordinación
  • Autoescalado avanzado: Picos de tráfico impredecibles, escalado basado en métricas custom
  • Multi-cloud o híbrido: Portabilidad entre proveedores cloud
  • Equipo dedicado: Tienes DevOps/SRE que pueden operar el cluster
  • Requisitos de disponibilidad: SLAs exigentes (99.9%+)
  • Ecosistema rico: Necesitas service mesh, GitOps, operators personalizados

Ejemplo Real: Fintech con 40 Microservicios

Arquitectura:
  Ingress Controller (NGINX)
    → API Gateway (Kong)
      → 40 microservicios en pods
      → 3 bases de datos (RDS)
      → Redis cluster
      → Kafka (event streaming)

Infraestructura:
  AWS EKS (3 nodos m5.xlarge + autoscaling)
  ArgoCD para GitOps
  Prometheus + Grafana para observabilidad
  cert-manager para TLS automático

Costo mensual: ~$2,000-3,500
Equipo necesario: 2-3 DevOps/SRE dedicados

Docker + Kubernetes: Cómo Trabajan Juntos

En la práctica, Docker y Kubernetes se complementan en un flujo continuo:

Developer escribe código

Docker build (crear imagen)

Docker push (subir a registro)

Kubernetes pull (descargar imagen)

Kubernetes deploy (crear pods)

Kubernetes manage (escalar, heal, update)

Pipeline CI/CD Completo

# GitHub Actions: build con Docker, deploy con Kubernetes
name: Build and Deploy
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Login to ECR
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and push Docker image
        run: |
          docker build -t $ECR_REGISTRY/mi-app:$GITHUB_SHA .
          docker push $ECR_REGISTRY/mi-app:$GITHUB_SHA

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Update Kubernetes deployment
        run: |
          aws eks update-kubeconfig --name my-cluster
          kubectl set image deployment/mi-app \
            mi-app=$ECR_REGISTRY/mi-app:$GITHUB_SHA
          kubectl rollout status deployment/mi-app

Alternativas a Kubernetes

Si Kubernetes es demasiado complejo para tu caso, considera estas alternativas:

AlternativaDescripciónCuándo Usarla
AWS ECS FargateContenedores managed sin servidoresAWS-only, equipos pequeños
Google Cloud RunContenedores serverlessTráfico variable, pay-per-request
Azure Container AppsContenedores managed con DaprEcosistema Microsoft
Docker SwarmOrquestación simple integrada en DockerClusters pequeños, baja complejidad
NomadOrquestador de HashiCorpMulti-workload (containers + VMs)
Railway/RenderPaaS con contenedoresStartups, prototipos rápidos

Errores Comunes

Error 1: Usar Kubernetes para Todo

Kubernetes tiene un costo operativo significativo. Si tienes un monolito o 2-3 servicios, Docker Compose o ECS Fargate son más eficientes. No uses un cañón para matar una mosca.

Error 2: Ignorar Docker Compose

Docker Compose es la mejor herramienta para desarrollo local. Incluso si tu producción usa Kubernetes, tu entorno local debería usar Compose para que los desarrolladores sean productivos sin necesitar un cluster.

Error 3: No Definir Resource Limits

En Kubernetes, siempre define requests y limits de CPU y memoria. Sin ellos, un pod puede consumir todos los recursos del nodo y afectar otros servicios.

Error 4: Imágenes Docker Enormes

Usa multi-stage builds y base images Alpine o distroless. Una imagen de 1.5GB es un problema de seguridad y de performance. Consulta nuestra guía de optimización de imágenes Docker para más detalles.

Decisión Final: Diagrama de Flujo

¿Cuántos servicios tienes?
  ├─ 1-3 servicios → Docker + Compose + ECS/Cloud Run
  ├─ 4-10 servicios → Evalúa: ¿necesitas autoescalado avanzado?
  │   ├─ No → ECS Fargate o Cloud Run
  │   └─ Si → Kubernetes (managed: EKS/GKE/AKS)
  └─ 10+ servicios → Kubernetes (managed)
      └─ ¿Tienes equipo SRE/DevOps dedicado?
          ├─ Si → EKS/GKE/AKS
          └─ No → Considera contratar o usar PaaS

Conclusión

Docker y Kubernetes no compiten: se complementan. Docker es la base para empaquetar aplicaciones en contenedores. Kubernetes agrega la capa de orquestación que necesitas cuando operas múltiples servicios en producción a escala.

La clave es elegir la complejidad adecuada para tu contexto. No adoptes Kubernetes porque es popular; adoptalo porque resuelve problemas reales que tienes hoy. Y si Docker solo o Docker con ECS/Cloud Run resuelven tu problema, esa es la mejor solución.

Para profundizar, consulta nuestra guía de virtualización y Linux para DevOps y cómo crear infraestructura inmutable con contenedores.