Ir al contenido
  1. Posts/

Docker Compose vs Kubernetes: cuándo usar cada uno

·1798 palabras·9 mins

He cometido el error dos veces ya. Montar algo “rapidito” en Docker Compose, que crece, se complica, y termino pasándolo a Kubernetes porque ya no puedo gestionarlo. Luego está el error contrario: montar un cluster K3s completo para hostear un solo contenedor que perfectamente podría vivir en un docker-compose.yml de tres líneas.

Después de gestionar ambos sistemas durante años en mi homelab (ahora mismo tengo varios equipos con Compose y un cluster K3s de tres nodos en ZimaBoard 2), creo que finalmente entiendo cuándo usar cada uno. Spoiler: no es solo “Compose para cosas simples, Kubernetes para lo complejo”. Es más sutil que eso.

Por qué esta pregunta importa en homelab
#

En producción empresarial la respuesta es fácil: Kubernetes. Tienes equipo, presupuesto, necesitas alta disponibilidad. Pero en homelab las reglas cambian. Tienes tiempo limitado. Presupuesto limitado. Paciencia limitada cuando algo se rompe a las 23:00 y solo quieres ver una película en Plex.

La pregunta real no es “¿cuál es mejor?” sino “¿cuál me va a hacer la vida más fácil para este caso concreto?”. He aprendido esto de la forma difícil.

Docker Compose: donde brilla (y donde duele)
#

Docker Compose es engañosamente simple. Un archivo YAML, un docker compose up -d, y listo. Esa simplicidad es real, pero tiene límites claros.

Lo que hace excepcionalmente bien
#

Compose es perfecto para stacks autónomos en un solo nodo. Mi Nextcloud personal lleva dos años en Compose sin problemas:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
services:
  nextcloud:
    image: nextcloud:latest
    restart: always
    ports:
      - "8080:80"
    volumes:
      - nextcloud_data:/var/www/html
    environment:
      - POSTGRES_HOST=db
      - POSTGRES_DB=nextcloud
      - POSTGRES_USER=nextcloud
      - POSTGRES_PASSWORD=secretpassword
    depends_on:
      - db

  db:
    image: postgres:15
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=nextcloud
      - POSTGRES_USER=nextcloud
      - POSTGRES_PASSWORD=secretpassword

volumes:
  nextcloud_data:
  db_data:

Esto funciona. Funciona bien. Lo actualizas con docker compose pull && docker compose up -d. Los logs con docker compose logs -f. Todo es predecible.

El desarrollo local también es territorio Compose. Cuando estoy probando un stack nuevo, empiezo siempre con Compose. Iterar es rápido. No necesito pensar en namespaces, deployments, services, ingress. Solo contenedores que hablan entre sí.

Donde empieza a doler
#

El problema llega cuando quieres más. Intenté montar mi stack de monitorización (Grafana, Prometheus, Loki, exporters) en Compose. Funcionó hasta que quise scraping de métricas de otros nodos. Compose no tiene service discovery real. Tienes que hardcodear IPs. Horrible.

Luego está el tema de updates con zero downtime. Compose hace docker stop y docker start. Tu servicio se cae esos segundos. Para Nextcloud personal no importa. Para algo que consultas cada minuto, molesta.

Y ni hablemos de storage compartido entre nodos. Porque Compose es single-node. Puedes hacer trucos con NFS mounts, pero ya estás parchando algo que no fue diseñado para eso.

Kubernetes (K3s): el martillo para tornillos complejos
#

K3s es Kubernetes sin el peso empresarial. Lo instalé en tres ZimaBoard 2 pensando “va a ser fácil”. No fue fácil. Pero una vez que lo dominas, puedes hacer cosas que en Compose son imposibles o muy feas.

Cuándo realmente lo necesitas
#

Alta disponibilidad real. Mi Gitea está en K3s con tres réplicas. Si un nodo se cae (y se caen, créeme), el servicio sigue vivo. Compose no puede darte esto.

Multi-nodo por diseño. Tengo workloads que corren en el nodo con más CPU, otros en el que tiene más RAM, otros en el que tiene GPU. K3s orquesta esto automáticamente con node selectors y taints.

Service discovery nativo. Todos los servicios se ven entre sí por nombre DNS interno. Prometheus encuentra automáticamente todos los pods para scraping. Magic.

Rolling updates sin caídas:

1
2
kubectl set image deployment/nextcloud nextcloud=nextcloud:28 --record
kubectl rollout status deployment/nextcloud

Ves las réplicas rotando una a una. El servicio nunca se cae. Esto en Compose requiere load balancers externos y orquestación manual.

El coste de entrada
#

Pero K3s tiene curva de aprendizaje. No es broma. Conceptos nuevos: Pods, Deployments, Services, Ingress, ConfigMaps, Secrets, PersistentVolumes, StorageClasses. El mismo Nextcloud que antes era 25 líneas de YAML ahora es:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nextcloud
  namespace: apps
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nextcloud
  template:
    metadata:
      labels:
        app: nextcloud
    spec:
      containers:
      - name: nextcloud
        image: nextcloud:28
        ports:
        - containerPort: 80
        env:
        - name: POSTGRES_HOST
          value: postgres-service
        - name: POSTGRES_DB
          valueFrom:
            secretKeyRef:
              name: nextcloud-secret
              key: database
        volumeMounts:
        - name: data
          mountPath: /var/www/html
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: nextcloud-pvc
---
apiVersion: v1
kind: Service
metadata:
  name: nextcloud-service
  namespace: apps
spec:
  selector:
    app: nextcloud
  ports:
  - port: 80
    targetPort: 80
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nextcloud-ingress
  namespace: apps
spec:
  rules:
  - host: nextcloud.homelab.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nextcloud-service
            port:
              number: 80

Y esto sin contar la base de datos (otro Deployment, Service, PVC), los Secrets, el StorageClass para los PVCs. Son muchas piezas.

Debugging también es más complejo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Ver pods
kubectl get pods -n apps

# Logs de un pod específico
kubectl logs nextcloud-7d8f9c5b4-xk2m9 -n apps

# Entrar en un pod para debugging
kubectl exec -it nextcloud-7d8f9c5b4-xk2m9 -n apps -- /bin/bash

# Ver eventos (cuando algo falla)
kubectl get events -n apps --sort-by='.lastTimestamp'

Cuando algo falla en Compose, miras los logs del contenedor. En K3s tienes que entender en qué capa está el problema: imagen, pod, deployment, service, ingress, network policy, storage.

Comparativa directa: misma app, dos enfoques
#

He montado el mismo stack de monitorización (Prometheus + Grafana) en ambos sistemas. Aquí está la realidad:

AspectoDocker ComposeKubernetes (K3s)
Tiempo setup inicial15 minutos3 horas (primera vez)
Líneas de config~40~200
Alta disponibilidadNo (single point of failure)Sí (réplicas multi-nodo)
Rolling updatesStop/start (downtime)Sin downtime
Service discoveryLinks/redes DockerDNS nativo
Gestión secretsVariables env en plaintextSecrets encriptados
Backup/restoreVolúmenes DockerSnapshots PV + Velero
Consumo recursos (idle)~100MB RAM~500MB RAM (overhead K3s)
Complejidad debuggingBajaMedia-Alta
Escalado horizontalManual (haproxy externo)Automático (HPA)
Persistencia multi-nodoImposible sin NFS externoNativa (Longhorn, Rook)

El overhead de K3s duele en hardware limitado. En una ZimaBoard 2 con 8GB RAM, K3s se come 400-500MB solo para funcionar. Compose apenas usa recursos propios.

Mi recomendación
#

Usa Docker Compose cuando:

  • Es un solo nodo y va a seguir siendo un solo nodo. No te mientas a ti mismo con “algún día lo escalaré”. Si no lo necesitas ahora, no lo necesitas.
  • Quieres algo funcionando YA. Compose es deploy en minutos. K3s es horas de setup más días de aprendizaje.
  • Es desarrollo o testing. Iterar en K3s es lento. Iterar en Compose es instantáneo.
  • El downtime de 10 segundos no importa. Actualizaciones, reinicios, lo que sea.

Ejemplos claros: Nextcloud personal, Jellyfin, Paperless-ngx, Vaultwarden, cualquier app self-hosted para ti y tu familia.

Usa Kubernetes (K3s) cuando:

  • Necesitas HA de verdad. Si el servicio debe estar vivo 24/7 incluso cuando un nodo se muere.
  • Tienes múltiples nodos y quieres aprovecharlos. K3s orquesta workloads entre nodos de forma inteligente.
  • El proyecto va a crecer en complejidad. Microservicios, service mesh, observabilidad compleja. Empezar con K3s desde el principio ahorra migraciones dolorosas.
  • Quieres aprender Kubernetes. K3s es la mejor forma de aprender sin pagar cloud.

Ejemplos: Gitea con HA, stack de monitorización (Prometheus, Grafana, Loki), CI/CD (GitLab, Jenkins), plataforma de ML/AI, cualquier cosa que sirvas a otros usuarios.

La mayoría de homelabbers no necesitan Kubernetes. Lo instalamos porque mola, porque es lo que “se usa en producción real”, porque queda bien en el CV. Pero un Portainer gestionando Compose stacks en varios nodos hace el 80% del trabajo con el 20% del esfuerzo.

Yo mantengo ambos. K3s para cosas serias (Gitea, monitorización, servicios críticos) en un cluster de ZimaBoard 2. Compose en el servidor Unraid y el Mac mini para servicios de soporte. Es el balance correcto para mi caso.

El camino de migración (cuando toca dar el salto)
#

Si empezaste con Compose y ahora necesitas K3s, el proceso duele menos de lo que piensas. He migrado seis stacks ya. El patrón es siempre el mismo:

1. Instala K3s en paralelo
#

No destruyas tu stack de Compose. Monta K3s en otro nodo (o en el mismo si tienes recursos). Deja Compose funcionando mientras aprendes.

1
2
3
4
5
6
7
8
9
# Nodo master
curl -sfL https://get.k3s.io | sh -

# Obtén el token
sudo cat /var/lib/rancher/k3s/server/node-token

# Nodos worker
curl -sfL https://get.k3s.io | K3S_URL=https://master-ip:6443 \
  K3S_TOKEN=tu-token sh -

2. Convierte el compose file pieza a pieza
#

Herramientas como Kompose ayudan pero generan YAML feo. Prefiero hacerlo a mano:

  • Cada service → un Deployment
  • Los ports → un Service (tipo ClusterIP o LoadBalancer)
  • Los volumesPersistentVolumeClaims
  • Las environment vars → ConfigMaps o Secrets
  • El routing → Ingress

3. Migra los datos
#

Esto es lo más delicado. Hice backup del volumen Docker, copié los datos al PV de K3s, verifiqué integridad. Para Postgres y MySQL hice dump/restore para estar seguro.

4. Cambia el DNS/proxy
#

Cuando el stack en K3s funciona, apuntas tu reverse proxy (Traefik, Nginx) al Ingress de K3s en lugar del puerto de Compose. Verifica que todo funciona. Deja Compose corriendo unos días más por si acaso.

5. Mata Compose cuando estés seguro
#

Solo después de una semana sin problemas borré los contenedores de Compose. Paranoia justificada después de perder datos una vez.

Conclusión práctica
#

He perdido fines de semana enteros peleándome con ambos sistemas. La lección más importante: no hay respuesta universal. Compose es brillante para su caso de uso. K3s es brillante para el suyo. Usar el equivocado es frustrante.

Empieza siempre con Compose. Cuando duela (y va a doler en algún momento si creces), entonces migra a K3s. No al revés. He visto gente intentar aprender K8s y Docker al mismo tiempo. Mal plan.

Y recuerda que puedes tener ambos. Mi homelab tiene Compose en el servidor Unraid para stacks pesados y en el Mac mini para servicios personales rápidos. K3s en el cluster de ZimaBoard 2 para infraestructura seria. Cada herramienta donde brilla.

¿Vas a montar tu primer homelab? Docker Compose. ¿Ya tienes tres nodos y quieres HA? K3s. ¿Algo intermedio? Probablemente Compose todavía, pero con un ojo puesto en K3s para cuando escales.

La tecnología correcta es la que te deja dormir tranquilo por la noche.