DevOps / Administración de Sistemas 8 min lectura

Backup automático de volúmenes Docker con Restic y systemd: guía práctica con retención y alertas

Configura backups cifrados, incrementales y automáticos de todos tus volúmenes Docker usando Restic. Programa las copias con systemd timer, define políticas de retención semanal/mensual y recibe notificaciones por correo si algo falla. Listo para producción en menos de 30 minutos.

Por Equipo Starbyte

Backup automático de volúmenes Docker con Restic y systemd: guía práctica con retención y alertas

Backup automático de volúmenes Docker con Restic y systemd: guía práctica con retención y alertas

Problema real: Tienes varios servicios Docker con volúmenes (bases de datos, configuraciones, archivos subidos por usuarios). Haces backups manuales de vez en cuando, o peor, no los haces. Un fallo de disco, un borrado accidental o un ataque de ransomware te costaría días de trabajo. Necesitas un sistema de backup automático, cifrado, eficiente (incremental) y con alertas, que no dependa de scripts frágiles ni de soluciones de pago.

Este post te guía para montar un sistema de backup con Restic, una herramienta moderna que soporta deduplicación, cifrado y múltiples destinos (local, S3, SFTP, etc.), integrado con los volúmenes Docker y gestionado por timers de systemd.


Requisitos previos

  • Servidor Linux con Docker y Docker Compose.
  • systemd como sistema de init (Ubuntu 20.04+, Debian 10+, etc.).
  • restic instalado (sudo apt install restic o binario desde GitHub).
  • Un destino para los backups:
    • Directorio local (ej. disco externo montado).
    • Repositorio remoto vía SFTP.
    • Bucket S3 compatible (AWS, MinIO, Backblaze B2, etc.).
  • mailutils o msmtp configurado para enviar correos (opcional, para alertas).

1. Flujo general del sistema

  1. Un script de backup (restic-backup.sh) inicia Restic, hace copia de los volúmenes Docker, aplica política de retención y registra el resultado.
  2. Un systemd service ejecuta ese script.
  3. Un systemd timer dispara el servicio a una hora programada (ej. 2:00 AM diario).
  4. Si falla, se envía un correo de alerta (usando OnFailure).

2. Estructura de directorios y variables

Crea una carpeta para el sistema de backup:

sudo mkdir -p /opt/backups
sudo mkdir -p /opt/backups/scripts
sudo mkdir -p /opt/backups/logs

Define las variables de entorno en un archivo que protegeremos:

sudo nano /opt/backups/restic-env

Contenido de ejemplo para repositorio local:

export RESTIC_REPOSITORY="/mnt/backup-disk/docker-volumes"
export RESTIC_PASSWORD="tu-contraseña-segura-backup"
export BACKUP_SOURCE="/var/lib/docker/volumes"
export RETENTION_DAYS=7
export RETENTION_WEEKS=4
export RETENTION_MONTHS=6

Para S3 sería:

export RESTIC_REPOSITORY="s3:s3.amazonaws.com/mi-bucket/backups"
export AWS_ACCESS_KEY_ID="tu-access-key"
export AWS_SECRET_ACCESS_KEY="tu-secret-key"
export RESTIC_PASSWORD="contraseña-fuerte"
# ... igual BACKUP_SOURCE y retenciones

Protege el archivo:

sudo chmod 600 /opt/backups/restic-env

3. Inicializar el repositorio Restic

Solo se hace una vez. Carga las variables y ejecuta:

source /opt/backups/restic-env
sudo -E restic init

El flag -E preserva las variables de entorno con sudo. Verás un mensaje de éxito.


4. Script de backup (restic-backup.sh)

sudo nano /opt/backups/scripts/restic-backup.sh

Contenido:

#!/bin/bash
set -euo pipefail

# Cargar variables
source /opt/backups/restic-env

LOG_FILE="/opt/backups/logs/backup-$(date +%Y%m%d-%H%M%S).log"

echo "=== Backup iniciado: $(date) ===" | tee "$LOG_FILE"

# Backup con exclusión de algunos directorios si se desea
restic backup "$BACKUP_SOURCE" \
    --verbose \
    --tag docker-volumes \
    --exclude="*.tmp" \
    --exclude="*.log" \
    2>&1 | tee -a "$LOG_FILE"

echo "=== Retención de snapshots ===" | tee -a "$LOG_FILE"

restic forget \
    --keep-daily $RETENTION_DAYS \
    --keep-weekly $RETENTION_WEEKS \
    --keep-monthly $RETENTION_MONTHS \
    --prune \
    2>&1 | tee -a "$LOG_FILE"

echo "=== Backup finalizado: $(date) ===" | tee -a "$LOG_FILE"

Hazlo ejecutable:

sudo chmod +x /opt/backups/scripts/restic-backup.sh

Explicación: El script hace backup del directorio de volúmenes de Docker (/var/lib/docker/volumes), que es donde residen los datos persistentes por defecto. Si usas volúmenes con paths personalizados, ajusta BACKUP_SOURCE o añade múltiples rutas.


5. Unidad de systemd para el backup

Crea el archivo de servicio:

sudo nano /etc/systemd/system/docker-volumes-backup.service
[Unit]
Description=Backup de volúmenes Docker con Restic
Wants=network-online.target
After=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/opt/backups/restic-env
ExecStart=/opt/backups/scripts/restic-backup.sh
User=root
Group=root

Ahora el timer que lo ejecutará diariamente a las 2:00 AM:

sudo nano /etc/systemd/system/docker-volumes-backup.timer
[Unit]
Description=Ejecuta backup de volúmenes Docker diario a las 2:00 AM
Requires=docker-volumes-backup.service

[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=1800

[Install]
WantedBy=timers.target

Nota: RandomizedDelaySec añade hasta 30 min de retraso aleatorio para evitar picos si tienes muchas máquinas.

Activa e inicia el timer:

sudo systemctl daemon-reload
sudo systemctl enable docker-volumes-backup.timer
sudo systemctl start docker-volumes-backup.timer

Verifica el estado:

sudo systemctl status docker-volumes-backup.timer
sudo systemctl list-timers --all

Para probar el servicio manualmente:

sudo systemctl start docker-volumes-backup.service
sudo journalctl -u docker-volumes-backup.service -f

6. Alertas por correo si el backup falla

Añade una unidad de systemd para notificar fallos. Crea el servicio de alerta:

sudo nano /etc/systemd/system/docker-volumes-backup-failure.service
[Unit]
Description=Alerta de fallo en backup Docker

[Service]
Type=oneshot
ExecStart=/usr/bin/mail -s "ALERTA: fallo backup Docker en $(hostname)" admin@dominio.com <<< "El backup de volúmenes Docker ha fallado. Revisa journalctl -u docker-volumes-backup.service"

Ahora vincula el OnFailure en el servicio principal. Edita docker-volumes-backup.service:

sudo nano /etc/systemd/system/docker-volumes-backup.service

Y añade la línea OnFailure=docker-volumes-backup-failure.service en la sección [Unit]:

[Unit]
Description=Backup de volúmenes Docker con Restic
Wants=network-online.target
After=network-online.target
OnFailure=docker-volumes-backup-failure.service

Recarga y ya está:

sudo systemctl daemon-reload

Para probar que la alerta funciona, simula un fallo temporalmente cambiando la ruta del script a una inexistente y ejecuta el servicio.


7. Verificación y restauración de respaldo

Listar snapshots:

source /opt/backups/restic-env
sudo -E restic snapshots

Montar un snapshot como sistema de archivos (vía FUSE) para inspeccionar:

sudo -E restic mount /mnt/restic-mount
# Navegar por /mnt/restic-mount y desmontar después: sudo umount /mnt/restic-mount

Restaurar un volumen específico a un directorio temporal:

sudo -E restic restore latest --target /tmp/restore-test --path /var/lib/docker/volumes/mi_volumen

8. Errores frecuentes y soluciones

Error Causa Solución
Fatal: unable to open repo: Is there a repo at ...? Repositorio no inicializado o ruta incorrecta Ejecuta restic init correctamente luego de cargar las variables de entorno.
Fatal: wrong password or no key found Contraseña incorrecta o perdida Asegúrate de que RESTIC_PASSWORD esté exportada correctamente y que el archivo restic-env tenga permisos 600.
permission denied al acceder a /var/lib/docker/volumes El script se ejecuta sin privilegios Añade User=root en el servicio systemd o ejecuta con sudo conservando variables (sudo -E).
El timer no se activa Persistent está en false y el sistema estuvo apagado en la hora programada Cambia Persistent=true para que ejecute en el siguiente arranque si se perdió la ventana.
Los snapshots no se borran tras forget Falta --prune Restic solo marca los snapshots para olvido; con --prune se eliminan los datos reales.
restic no encuentra comando mount Falta FUSE Instala fuse y asegúrate de que el módulo del kernel esté cargado (modprobe fuse).

9. Casos prácticos de uso

9.1 Backup a Backblaze B2

Añade al archivo restic-env:

export RESTIC_REPOSITORY="b2:nombre-bucket:/docker-backups"
export B2_ACCOUNT_ID="tu-account-id"
export B2_ACCOUNT_KEY="tu-application-key"
export RESTIC_PASSWORD="password-muy-fuerte"

9.2 Deduplicación entre múltiples hosts

Usa el mismo repositorio S3 desde diferentes servidores añadiendo --host en el comando de backup para diferenciar orígenes:

restic backup --host servidor-web-1 --tag prod /var/lib/docker/volumes

Restic deduplica bloques incluso entre máquinas distintas.

9.3 Backup pre- y post-script para bases de datos

Para PostgreSQL, antes del backup principal, vuelca la base de datos a un archivo en un volumen o directorio temporal:

docker exec postgres pg_dump -U user db > /var/lib/docker/volumes/dumps/db.sql

Añade esa línea al inicio del script de backup, y al final opcionalmente la eliminas. Así la copia incluye el dump consistente.


10. Buenas prácticas

  • Cifra el archivo de entorno con gpg o usa un gestor de secretos, especialmente si contiene claves de nube.
  • Ubica el repositorio local en un disco externo y no en la misma unidad que respaldas. Si es remoto, usa siempre transporte TLS.
  • Prueba la restauración periódicamente (al menos una vez al mes) en un entorno de staging.
  • Configura RETENTION_* según la importancia de los datos. No acumules snapshots infinitos; Restic puede consumir mucho espacio si no pruning.
  • Añade --verbose y redirige logs a un archivo rotativo o a syslog para depuración.
  • Usa RESTIC_PASSWORD_COMMAND en lugar de RESTIC_PASSWORD si prefieres leer la contraseña desde un archivo secreto o comando (ej. pass).
  • Monitoriza el timer con systemd (p.ej., systemctl status docker-volumes-backup.timer) y añade un chequeo de antigüedad del último snapshot en tu monitorización (Prometheus + node_exporter textfile collector).

11. Cierre con idea clave

Los backups manuales no son backups. Con Restic y systemd consigues un sistema de copias de seguridad de volúmenes Docker que es automático, cifrado, con retención inteligente y alertas. Una vez configurado, olvídate del miedo a perder datos y dedica tu tiempo a lo que realmente importa: construir tus aplicaciones.

Etiquetas: #docker #restic #backup #systemd #volumenes #automatizacion