Problema

En entornos donde Proxmox hospeda un NAS basado en ZFS y expone los datasets mediante NFS o SMB, es frecuente mover la capa de servicios (SMB/NFS) a un contenedor LXC. El contenedor utiliza bind‑mounts o mp0 para acceder a los datasets del host. El reto surge al intentar respaldar tanto la configuración del LXC como los datos reales que residen fuera del rootfs del contenedor. Un backup que solo incluye el contenedor deja los volúmenes montados sin protección; incluirlos dentro del contenedor inflaría el tamaño del backup y complicaría la restauración.

Causa

  1. Separación de capas – Proxmox separa el rootfs del contenedor de los puntos de montaje externos. Los snapshots de LXC no capturan los datasets montados.
  2. ZFS sin snapshots coordinados – Cuando se crea un snapshot de ZFS del pool, los datasets que están en uso por NFS/SMB pueden quedar inconsistentes si no se detienen o se ponen en modo de solo lectura.
  3. Herramientas de backup distintas – Proxmox Backup Server (PBS) gestiona LXC de forma nativa, pero no incluye automáticamente los bind‑mounts. El cliente PBS en el host sí puede respaldar directorios arbitrarios, pero requiere una planificación de jobs separada.
  4. Cron vs jobs integrados – Confiar solo en la programación de PBS desde la UI puede omitir la sincronización entre snapshot ZFS y backup PBS, generando copias de datos en estado intermedio.

Solución

1. Definir dos flujos de backup independientes pero coordinados

Flujo Qué respalda Herramienta Comentario
A Configuración y rootfs del LXC PBS (job LXC) Rápido, deduplicado, restaurable con un solo comando.
B Datasets montados (NFS/SMB) PBS client o zfs send + zfs receive Usa snapshots para consistencia; puede ejecutarse desde cron.

2. Preparar snapshots ZFS antes de cada backup

  1. Crear un snapshot del pool que contiene los datasets que el contenedor exporta.
  2. Marcar el snapshot como “readonly” para evitar escrituras durante el envío.
# pool = tank, dataset = tank/nas
zfs snapshot -r tank/nas@backup-$(date +%Y%m%d%H%M)
zfs hold -r backup-$(date +%Y%m%d%H%M) tank/nas@backup-$(date +%Y%m%d%H%M)

3. Configurar el job PBS para el contenedor

En la UI de PBS o vía API, crear un job con:

  • Tipo: LXC
  • ID del contenedor: <CTID>
  • Retención: según política (ej. 30 días)
  • Excluir mp0/mp1 si aparecen como bind‑mounts (no se necesita, PBS ignora los puntos externos).

4. Respaldar los datasets con el cliente PBS

El cliente PBS permite enviar cualquier ruta a un repositorio PBS. Usamos la snapshot como origen para garantizar consistencia.

# Variables
REPO="pbs.example.com:backup"
TOKEN="my-token"
SNAP="tank/nas@backup-$(date +%Y%m%d%H%M)"
TARGET="nas/$(hostname)/$(date +%Y%m%d%H%M)"

# Envío
proxmox-backup-client backup \
  --repository $REPO \
  --store $TARGET \
  --snapshot $SNAP \
  --token $TOKEN \
  --compression zstd

5. Orquestar con cron

# /etc/cron.d/proxmox-backup
0 2 * * * root /usr/local/sbin/backup-proxmox.sh >> /var/log/backup-proxmox.log 2>&1

backup-proxmox.sh encapsula los pasos 2‑4, garantizando que el snapshot se crea, se envía y luego se destruye:

#!/bin/bash
set -euo pipefail

SNAP_NAME="backup-$(date +%Y%m%d%H%M)"
zfs snapshot -r tank/nas@${SNAP_NAME}
zfs hold -r ${SNAP_NAME} tank/nas@${SNAP_NAME}

/usr/local/bin/pbs-client-send.sh ${SNAP_NAME}

/usr/bin/zfs release -r ${SNAP_NAME} tank/nas@${SNAP_NAME}

pbs-client-send.sh contiene el comando proxmox-backup-client backup mostrado antes.

6. Restaurar

  • LXC: pct restore <newCTID> <backup-id>.tar.gz (o vía UI PBS).
  • Datasets: crear un nuevo snapshot a partir del backup recibido y montar o clonar:
proxmox-backup-client restore \
  --repository $REPO \
  --store $TARGET \
  --snapshot $SNAP_RESTORED \
  --path /tank/nas_restored
zfs clone tank/nas_restored@latest tank/nas_restore

Cuándo aplicar esta solución

  • Entornos con ZFS y datasets expuestos mediante NFS/SMB.
  • Contenedores LXC que usan bind‑mounts para compartir storage.
  • Necesidad de retención granular (p.ej. 30 días) y deduplicación para datos masivos.
  • No es adecuada si el NAS está en un pool distinto sin ZFS (no hay snapshots consistentes).
  • Si el objetivo es un backup “todo‑en‑uno” sin preocuparse por el tamaño, se puede incluir los mount points dentro del contenedor, pero perderás la ventaja de snapshots ZFS.

Código

# 1. Crear snapshot ZFS
zfs snapshot -r tank/nas@backup-$(date +%Y%m%d%H%M)

# 2. Enviar snapshot a PBS
proxmox-backup-client backup \
  --repository pbs.example.com:backup \
  --store nas/$(hostname)/$(date +%Y%m%d%H%M) \
  --snapshot tank/nas@backup-$(date +%Y%m%d%H%M) \
  --token my-token \
  --compression zstd

# 3. Liberar snapshot
zfs release -r backup-$(date +%Y%m%d%H%M) tank/nas@backup-$(date +%Y%m%d%H%M)

Verificación

  1. Listar backups en PBS: proxmox-backup-client list --repository pbs.example.com:backup.
  2. Verificar integridad del snapshot remoto: proxmox-backup-client check --repository … --store ….
  3. Restaurar en un entorno de pruebas y montar los datasets restaurados; validar que los shares NFS/SMB siguen exportándose sin errores.
  4. Ejecutar pct status <CTID> después de restaurar el contenedor para confirmar que arranca y que los bind‑mounts apuntan a los datasets restaurados.

Notas adicionales

  • Bloqueo de escritura: si los datasets están en uso intensivo, considera montar temporalmente en modo ro antes del snapshot (zfs set readonly=on tank/nas).
  • Retención de snapshots: programa una tarea de limpieza (zfs destroy -r tank/nas@backup-*) para evitar que el pool se llene.
  • Compresión: ZSTD ofrece buen equilibrio entre velocidad y reducción de tamaño; ajusta el nivel si el ancho de banda del repositorio es limitado.
  • Seguridad: usa tokens de corta duración para el cliente PBS y restringe el acceso al repositorio mediante firewall.
  • Monitorización: incluye la salida de backup-proxmox.sh en un sistema de alertas (ex. Prometheus node exporter) para detectar fallos antes de que se acumulen.