Problema

En muchos homelabs de bajo presupuesto el disco de arranque es un SSD pequeño mientras que el almacenamiento de datos se encuentra en un HDD más lento. Sistemas como TrueNAS SCALE reservan el SSD exclusivamente para el sistema operativo y los servicios de gestión, lo que obliga a que contenedores y máquinas virtuales utilicen el HDD para sus volúmenes de trabajo. El resultado típico es un cuello de botella de I/O: aplicaciones de medios, bases de datos ligeras o servicios con caché se ven limitadas por la velocidad de 5400 rpm.

El patrón se repite en entornos donde se combina NAS y plataforma de contenedores en una única instalación: el usuario quiere aprovechar la rapidez del SSD para los procesos críticos, pero la arquitectura del software impide mover esos volúmenes sin re‑instalar o reconfigurar profundamente. La pregunta central es si una capa de virtualización (Proxmox) con una VM Linux que ejecute Docker ofrece una ruta más flexible para asignar el SSD a los contenedores y dejar el HDD solo para datos estáticos.

Causa

  1. Diseño de TrueNAS SCALE – El sistema está pensado como un appliance de almacenamiento. El boot pool está aislado y no está pensado para albergar workloads de alto I/O fuera del propio NAS.
  2. Falta de separación de discos en el nivel de contenedor – Cuando se despliegan aplicaciones desde el catálogo, el motor de contenedores interno (Kubernetes/Containerd) monta los volúmenes directamente sobre el pool de datos, que normalmente reside en el HDD.
  3. Limitaciones de hardware – En equipos con 8 GB de RAM y CPU de segunda generación, el overhead de un hipervisor ligero como Proxmox es marginal comparado con el beneficio de poder asignar directamente el SSD a una VM.
  4. Configuración de almacenamiento predeterminada – Proxmox permite crear discos virtuales (raw, qcow2) o volúmenes LVM/ZFS en cualquier disco detectado. Si el administrador no define un “storage pool” en el SSD, los discos de la VM se crean automáticamente en el HDD.

En conjunto, estas causas hacen que el SSD quede subutilizado mientras el HDD se vuelve el cuello de botella.

Solución

Una arquitectura basada en Proxmox → VM Ubuntu Server → Docker ofrece tres ventajas clave:

  1. Control total del layout de discos – En Proxmox se crea un storage pool exclusivo en el SSD (por ejemplo, local-ssd con ZFS o LVM). Los discos virtuales de la VM se almacenan allí, garantizando que el sistema operativo y los contenedores tengan acceso a I/O rápido.
  2. Aislamiento de servicios – Cada aplicación se ejecuta dentro de su propio contenedor Docker, lo que simplifica la gestión de dependencias y permite mover volúmenes entre discos sin tocar el hipervisor.
  3. Escalabilidad futura – Añadir más discos o migrar a un clúster Proxmox es trivial; los contenedores siguen funcionando mientras se re‑asignan los storage pools.

Paso a paso práctico

  1. Instalar Proxmox VE en el SSD. Durante la instalación, elige el disco de arranque como local-ssd y habilita ZFS (o LVM) si buscas snapshots y checksums.
  2. Crear un storage pool en el HDD llamado data-hdd para almacenar archivos multimedia, bases de datos de gran tamaño y backups.
  3. Crear una VM Ubuntu Server: asigna 2 vCPU, 4 GB RAM (ajustable) y un disco virtual de 30 GB en local-ssd.
  4. Instalar Docker dentro de la VM siguiendo la guía oficial (apt repository, docker-ce).
  5. Montar volúmenes Docker apuntando a directorios en el HDD mediante bind‑mounts. Por ejemplo, /srv/media en la VM se enlaza a /mnt/data-hdd/media en el storage pool data-hdd.
  6. Desplegar contenedores (Jellyfin, Immich, Radarr, Sonarr, etc.) usando docker compose o archivos docker run. Cada contenedor tiene su carpeta de configuración en el SSD y sus datos pesados en el HDD.

Esta separación permite que la carga de metadatos, cachés y procesos de transcodificación se beneficie del SSD, mientras que los archivos de video, fotos y torrents permanecen en el HDD.

Cuándo aplicar esta solución

  • Cuello de botella de I/O: notas que la transcodificación, carga de thumbnails o consultas de bases de datos son lentas pese a tener un SSD disponible.
  • Necesidad de aislar servicios: deseas actualizar o reiniciar un contenedor sin afectar al resto del sistema.
  • Hardware limitado: solo dispones de 8 GB RAM y un SSD pequeño; la sobrecarga de Proxmox es mínima y la flexibilidad compensa el consumo extra.
  • Plan de expansión: piensas añadir más discos o migrar a un clúster en el futuro.

No aplicar si tu NAS ya está optimizado con ZFS cache (L2ARC) y la carga de trabajo es principalmente de backup sin transcodificación, o si el SSD tiene suficiente capacidad para albergar tanto el OS como los datos críticos.

Código

# 1. Crear storage pool en SSD (ZFS)
pvesm add zfspool local-ssd --pool ssd-pool --content images,rootdir

# 2. Crear storage pool en HDD
pvesm add lvm data-hdd --vgname hdd-vg --content images,rootdir

# 3. Crear VM Ubuntu (ID 101) con disco en SSD
qm create 101 --name ubuntu-docker --memory 4096 --cores 2 \
  --net0 virtio,bridge=vmbr0 \
  --scsihw virtio-scsi-pci \
  --ide2 local:cloudinit \
  --boot c --bootdisk scsi0

qm set 101 --scsi0 local-ssd:30,format=raw
qm set 101 --serial0 socket --vga serial0

# 4. Iniciar VM y conectar via SSH
qm start 101
ssh ubuntu@<IP_VM>

# 5. Dentro de la VM: instalar Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
usermod -aG docker $USER
newgrp docker

# 6. Montar HDD dentro de la VM (asumiendo LVM)
sudo mkdir -p /mnt/data-hdd
sudo mount /dev/mapper/hdd--vg-data /mnt/data-hdd
sudo chown $(whoami):$(whoami) /mnt/data-hdd

# 7. Ejemplo docker-compose para Jellyfin
cat > docker-compose.yml <<'EOF'
version: "3.8"
services:
  jellyfin:
    image: jellyfin/jellyfin:latest
    container_name: jellyfin
    network_mode: host
    volumes:
      - /etc/jellyfin:/config
      - /mnt/data-hdd/media:/media
    restart: unless-stopped
EOF

docker compose up -d

Verificación

  1. Comprobar ubicación del disco virtual
    qm config 101 | grep scsi0
    # Debería mostrar local-ssd como storage
    
  2. Validar que Docker usa el SSD para configuraciones
    docker inspect jellyfin | grep Mounts
    # Los paths de /config deben estar bajo la raíz del SSD
    
  3. Medir I/O
    • Ejecuta iostat -xz 1 5 dentro de la VM mientras Jellyfin transcodifica.
    • Los valores de await y svctm deben ser significativamente menores que los obtenidos cuando el contenedor usa el HDD directamente.
  4. Revisar logs de Proxmox para asegurarse de que no hay errores de I/O en local-ssd.

Notas adicionales

  • Snapshots: ZFS en el SSD permite snapshots rápidos de la VM completa; útil antes de actualizar contenedores.
  • L2ARC: Si el HDD contiene datos que se leen frecuentemente, considera habilitar un L2ARC en el SSD para acelerar lecturas sin mover los datos.
  • Memoria: Con 8 GB de RAM, monitoriza el uso de swap dentro de la VM; Docker puede consumir más memoria de la esperada cuando varios contenedores están activos.
  • Backup: Usa vzdump de Proxmox para respaldar la VM completa; los volúmenes de datos en el HDD pueden respaldarse con rsync o zfs send.
  • Actualizaciones de Proxmox: Mantén el host actualizado, pero prueba primero en una VM de prueba antes de aplicar cambios críticos al nodo de producción.