Problema

Muchos entusiastas de homelab y pequeñas empresas quieren los beneficios de Kubernetes —aislamiento de red, despliegues declarativos, escalado sencillo— pero no pueden justificar la sobrecarga de recursos y la complejidad operativa que implica mantener varios nodos, certificados y control planes. El resultado típico es un clúster que consume entre el 15 % y el 25 % de la CPU/RAM disponible sin aportar carga útil real, o que sufre downtime por expiración de certificados y falta de HA. El reto es conseguir una capa de orquestación suficientemente flexible para:

  • Ejecutar stacks como Plex con tráfico aislado del resto de los servicios.
  • Desplegar aplicaciones “fire‑and‑forget” que se actualicen automáticamente.
  • Probar ideas rápidamente en un entorno de laboratorio sin interferir con los servicios productivos.
  • Mantener una curva de aprendizaje que exponga los conceptos de contenedores sin la burocracia de un clúster completo.

Causa

  1. Sobredimensionamiento del plano de control – Instalar un control‑plane completo (etcd, kube‑apiserver, scheduler) en hardware limitado genera un consumo constante de recursos que no escala con la carga de trabajo real.
  2. Gestión manual de certificados – En Kubernetes los certificados del control‑plane expiran por defecto a un año; la falta de automatización para su renovación provoca caídas inesperadas.
  3. Redes superpuestas – Usar CNI como Calico sin una configuración adecuada obliga a crear VLANs o redes dedicadas, lo que complica la topología y aumenta la latencia.
  4. Falta de separación de entornos – Ejecutar todos los workloads en el mismo clúster obliga a aplicar políticas de red complejas y a gestionar namespaces con precisión, algo que suele fallar en entornos domésticos.
  5. Curva de aprendizaje de Kubernetes – Los conceptos de Pods, Deployments, StatefulSets y CRDs son valiosos, pero para un homelab pueden resultar excesivos cuando el objetivo es simplemente lanzar contenedores aislados.

Solución

Una combinación de Docker Compose (o Podman‑compose) para la definición declarativa y systemd‑networkd + iptables para aislamiento de red ofrece la mayor parte de la funcionalidad que se busca, con una huella mínima. Para CI/CD se puede añadir Watchtower (actualizaciones automáticas) o GitHub Actions que ejecuten docker compose up -d. Cuando se necesita aislamiento a nivel de VM, Proxmox sigue siendo la capa de virtualización; dentro de cada VM se ejecuta Docker Compose con una red bridge dedicada.

Arquitectura recomendada

  1. Host físico → Proxmox (o cualquier hipervisor ligero).
  2. VM “infra” → Debian/Ubuntu minimal, Docker Engine, Docker Compose.
  3. Redes
    • br0 (bridge) conectado a la NIC física, usado por los contenedores que deben estar expuestos.
    • br_isolated (bridge interno) sin salida a la NIC, usado por stacks que requieren aislamiento total (ej. Plex).
  4. Reverse proxy → Traefik o Caddy en modo Docker, gestiona el enrutamiento entre redes y provee TLS automática con Let’s Encrypt.
  5. Actualizaciones automáticas → Watchtower monitoriza los repositorios y redeploya versiones :latest.

Esta arquitectura permite:

  • Aislamiento de red mediante bridges y reglas iptables específicas por proyecto.
  • Despliegues declarativos usando un único archivo docker-compose.yml.
  • CICD sencillo con GitHub Actions que actualizan el repositorio y disparan docker compose pull && docker compose up -d.
  • Bajo consumo: el host solo ejecuta Docker y el proxy, sin procesos de control‑plane adicionales.

Alternativas prácticas

Necesidad Herramienta ligera Comentario
Orquestación sin clúster Nomad (HashiCorp) Scheduler simple, UI mínima, pero requiere Consul para descubrimiento.
Aislamiento de red avanzado Cilium en modo “CNI-less” Usa eBPF, pero implica kernel más reciente.
Gestión de múltiples VMs Ansible + cloud‑init Automatiza la creación de VMs y la instalación de Docker.

Cuándo aplicar esta solución

  • Recursos limitados – Cuando el hardware disponible no supera 8 CPU y 16 GB RAM.
  • Entornos mixtos – Necesitas separar tráfico de Plex, servicios de hosting y laboratorios sin crear varios clústers.
  • Curva de aprendizaje controlada – Quieres entender contenedores, redes y CI/CD sin la sobrecarga de objetos de Kubernetes.
  • Mantenimiento reducido – Prefieres que la única pieza crítica sea Docker, que se actualiza con un solo comando.

No es adecuada si:

  • Requieres autoscaling a gran escala o balanceo de carga multi‑region.
  • Necesitas stateful workloads con alta disponibilidad (por ejemplo, bases de datos distribuidas).
  • Tu equipo ya domina Kubernetes y busca características avanzadas como operators o custom resources.

Código

# Crear bridges en el host (ejemplo en Debian/Ubuntu)
cat <<EOF > /etc/systemd/network/25-br0.netdev
[NetDev]
Name=br0
Kind=bridge
EOF

cat <<EOF > /etc/systemd/network/26-br0.network
[Match]
Name=br0
[Network]
Address=192.168.100.1/24
DHCPServer=yes
EOF

cat <<EOF > /etc/systemd/network/27-br_isolated.netdev
[NetDev]
Name=br_isolated
Kind=bridge
EOF

cat <<EOF > /etc/systemd/network/28-br_isolated.network
[Match]
Name=br_isolated
[Network]
Address=10.10.10.1/24
EOF

systemctl restart systemd-networkd

# docker‑compose.yml para Plex aislado
cat <<'EOF' > docker-compose.yml
version: "3.9"
services:
  plex:
    image: linuxserver/plex
    container_name: plex
    restart: unless-stopped
    network_mode: "bridge"
    ports:
      - "32400:32400"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/Madrid
    volumes:
      - ./plex/config:/config
      - ./plex/media:/media
    # Conectar a bridge aislado
    networks:
      isolated:
        ipv4_address: 10.10.10.10

networks:
  isolated:
    driver: bridge
    ipam:
      config:
        - subnet: 10.10.10.0/24
EOF

docker compose up -d

Verificación

  1. Aislamiento de red – Desde el host, intenta curl http://10.10.10.10:32400/web. Debería responder solo dentro del bridge aislado.
  2. Acceso externo – Accede a http://<IP_FISICA>:32400/web y verifica que el tráfico pasa por la regla iptables -A FORWARD -i br_isolated -j DROP si deseas bloquearlo completamente.
  3. Actualizaciones automáticas – Instala Watchtower: docker run -d --name watchtower -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower. Cambia la etiqueta de la imagen en docker-compose.yml a :latest y observa que Watchtower redeploya el contenedor tras un docker pull.
  4. CI/CD – Configura un workflow de GitHub Actions que ejecute docker compose pull && docker compose up -d. Verifica que el pipeline termina sin errores y que los contenedores se reinician con la nueva versión.

Notas adicionales

  • Persistencia de datos – Monta volúmenes en directorios fuera del directorio del proyecto para evitar pérdidas al recrear stacks.
  • Backups – Usa rsync o restic para copiar los volúmenes a un NFS o a un bucket S3.
  • Monitorización ligeracAdvisor + Grafana en un contenedor separado brinda métricas de CPU/RAM sin necesidad de Prometheus completo.
  • Seguridad de la red – Añade reglas iptables que permitan solo puertos necesarios entre bridges; evita --network host a menos que sea estrictamente necesario.
  • Escalado futuro – Si la carga crece, migrar a K3s o a un clúster de Nomad es un paso natural porque la definición ya está en docker-compose.yml, que puede convertirse en Helm charts con pocas modificaciones.