Problema

En entornos con Proxmox VE es frecuente montar un pool ZFS en el host y exponerlo a un contenedor LXC mediante bind mount para servir archivos con Samba. El desafío surge al diseñar la estrategia de respaldo con Proxmox Backup Server (PBS): ¿debería PBS respaldar solo el disco raíz del contenedor o incluir también los datos del pool ZFS que están montados dentro del LXC? Además, muchos administradores se preguntan si colocar el sistema operativo del host y los discos raíz de máquinas virtuales/LXC en el mismo SSD RAID‑1 es una práctica segura o si genera cuellos de botella.

Causa

1. Separación lógica vs. física de datos

Los contenedores LXC son esencialmente procesos aislados; su sistema de archivos raíz está en un subvolumen ZFS o en un directorio del host. Cuando se hace bind mount de un dataset ZFS externo, el contenedor ve esos datos como parte de su árbol, pero PBS, al trabajar a nivel de subvolumen del contenedor, no tiene visibilidad directa del dataset externo. Si se configura una tarea de backup que solo apunta al subvolumen del contenedor, los archivos del dataset quedan fuera del snapshot y, por tanto, fuera del respaldo.

2. Snapshots y consistencia de ZFS

ZFS permite snapshots atómicos de datasets completos. Si el dataset está montado dentro del contenedor y se modifica mientras PBS crea un backup, el snapshot del contenedor no captura esos cambios. La única forma de garantizar consistencia es crear un snapshot del dataset ZFS antes de que PBS lo incluya en la copia.

3. Uso intensivo del SSD para OS + VM roots

Un SSD en espejo (RAID‑1) ofrece redundancia y buen rendimiento, pero si el mismo espejo aloja tanto el sistema operativo del host como los discos raíz de todas las VMs/LXC, cualquier I/O intensivo de backup o de la carga de trabajo de Samba compite por el mismo recurso. En entornos SMB con varios TB de datos, esa competencia puede traducirse en latencias notables y mayor desgaste del SSD.

Solución

Estrategia de backup híbrida

  1. Separar los datasets

    • Mantener el dataset ZFS que contiene los datos de Samba en su propio pool o al menos en un dataset independiente (tank/samba-data).
    • El contenedor LXC tiene su propio dataset (tank/lxc-samba-root) que solo contiene la configuración y los binarios de Samba.
  2. Configurar PBS para respaldar ambos datasets

    • Crear dos trabajos de backup en PBS:
      a) Root backup: apunta al subvolumen del contenedor (/var/lib/vz/snippets/lxc-samba-root).
      b) Data backup: apunta al dataset ZFS externo (/mnt/samba-data).
    • En el trabajo de Data backup habilitar la opción --snapshot para que PBS solicite a ZFS un snapshot antes de copiar.
  3. Automatizar snapshots con hooks

    • Utilizar los hook scripts de Proxmox (/etc/pve/lxc/<CTID>.conf) para ejecutar zfs snapshot justo antes de que PBS inicie el backup del dataset externo.
    • El hook también puede destruir el snapshot después de que PBS confirme la transferencia, evitando la proliferación de snapshots.
  4. Revisar la arquitectura de discos

    • Mantener el SSD RAID‑1 exclusivamente para el sistema operativo del host y los discos raíz de VMs/LXC que requieren alta velocidad (por ejemplo, bases de datos pequeñas).
    • Reservar los HDDs en el pool ZFS para datos de usuario, backups y archivos de Samba.
    • Si el presupuesto lo permite, agregar un SSD dedicado para los snapshots de ZFS (tank/snapshots) de modo que la escritura de snapshots no impacte el rendimiento del pool de datos.

Implementación paso a paso

a) Creación de datasets

# Dataset para el root del contenedor LXC
zfs create -o mountpoint=/var/lib/vz/snippets/lxc-samba-root tank/lxc-samba-root

# Dataset para los archivos de Samba
zfs create -o mountpoint=/mnt/samba-data tank/samba-data

b) Bind mount en el contenedor

Edita la configuración del contenedor (/etc/pve/lxc/101.conf):

mp0: /mnt/samba-data,mp=/srv/samba,bind=1

c) Hook script para snapshots

Crea /etc/pve/lxc/101.hookscript:

#!/bin/bash
# $1 = pre-start | post-stop | pre-backup | post-backup
if [ "$1" = "pre-backup" ]; then
    zfs snapshot tank/samba-data@pbs-$(date +%Y%m%d%H%M%S)
elif [ "$1" = "post-backup" ]; then
    zfs destroy tank/samba-data@pbs-$(date +%Y%m%d%H%M%S)
fi

Hazlo ejecutable y enlázalo en la configuración:

hookscript: /etc/pve/lxc/101.hookscript

d) Configuración de PBS

En la interfaz web de PBS crea dos Backup Jobs:

  • Job 1LXC Root:

    • Source: proxmox-host:/tank/lxc-samba-root
    • Type: LXC
    • No snapshot (el contenedor ya está detenido o en modo freeze).
  • Job 2Samba Data:

    • Source: proxmox-host:/tank/samba-data@pbs-*
    • Type: Filesystem
    • Enable snapshot (PBS enviará zfs snapshot automáticamente si el host tiene el daemon zfs habilitado).

Ventajas

  • Consistencia: Cada backup de datos incluye un snapshot ZFS atómico, evitando archivos corruptos.
  • Escalabilidad: Los datasets pueden crecer independientemente; los snapshots no afectan al pool de datos.
  • Rendimiento: Separar SSD y HDD reduce la contención de I/O y prolonga la vida útil del SSD.

Cuándo aplicar esta solución

  • Entornos con bind mounts: Si cualquier contenedor LXC consume datasets ZFS externos, la estrategia híbrida es la más segura.
  • Alto volumen de datos: Cuando el pool ZFS supera varios terabytes y los backups deben ser consistentes sin detener el servicio.
  • Infraestructura con SSD limitado: Si el SSD está destinado al host y a VMs críticas, mover los datos de usuario a HDD evita cuellos de botella.
  • No aplicar: En despliegues muy pequeños (p.ej., un único contenedor con <100 GB) donde la complejidad del hook script no justifica el beneficio; en ese caso un backup simple del contenedor puede ser suficiente.

Código

# Crear datasets
zfs create -o mountpoint=/var/lib/vz/snippets/lxc-samba-root tank/lxc-samba-root
zfs create -o mountpoint=/mnt/samba-data tank/samba-data

# Configurar bind mount en LXC
echo "mp0: /mnt/samba-data,mp=/srv/samba,bind=1" >> /etc/pve/lxc/101.conf

# Hook script (pre-backup / post-backup)
cat > /etc/pve/lxc/101.hookscript <<'EOF'
#!/bin/bash
if [ "$1" = "pre-backup" ]; then
    zfs snapshot tank/samba-data@pbs-$(date +%Y%m%d%H%M%S)
elif [ "$1" = "post-backup" ]; then
    zfs destroy tank/samba-data@pbs-$(date +%Y%m%d%H%M%S)
fi
EOF
chmod +x /etc/pve/lxc/101.hookscript
echo "hookscript: /etc/pve/lxc/101.hookscript" >> /etc/pve/lxc/101.conf

Verificación

  1. Comprobar snapshot
    Ejecuta zfs list -t snapshot | grep pbs- antes y después de iniciar el backup. Debería aparecer y luego desaparecer tras el post-backup.

  2. Validar backup en PBS
    En la UI de PBS verifica que ambos jobs aparecen como Successful y que el tamaño del backup de datos coincide con el uso del dataset (zfs get used tank/samba-data).

  3. Prueba de restauración

    • Restaura el dataset en un entorno de pruebas: zfs rollback tank/samba-data@pbs-<timestamp>.
    • Monta el contenedor y verifica que Samba sigue sirviendo los archivos sin errores.
  4. Monitoreo de I/O
    Usa iostat -x 5 o zpool iostat -v tank 5 para observar que durante el backup el SSD no muestra picos de escritura inesperados.

Notas adicionales

  • Retención de snapshots: Si el hook script falla y deja snapshots huérfanos, programa una tarea cron que elimine snapshots viejos (zfs destroy -r tank/samba-data@pbs-* con una política de retención de 7‑14 días).
  • Compresión ZFS: Activar compression=lz4 en tank/samba-data reduce el espacio necesario tanto en disco como en el backup, sin penalizar el rendimiento de Samba.
  • Seguridad: Asegúrate de que el usuario que ejecuta PBS tenga permisos de zfs allow sobre el dataset, evitando que el proceso sea root por completo.
  • Off‑site: PBS permite replicar backups a otro servidor PBS mediante remote repositories. Configura una replicación diaria del job de datos para cumplir con la política de copia off‑site sin sobrecargar el host principal.