Backups automáticos con rsync y cron para Docker doméstico

Etiquetas:

El problema

Hace poco perdí un disco duro sin previo aviso. No fue catastrófico porque tenía backups, pero me hizo consciente de que muchos hobbistas con servidores domésticos no tienen ninguna estrategia de protección de datos. Si tu servidor Docker se cae mañana, ¿cuánto tiempo tardarías en recuperarlo?

En este artículo comparto cómo automaticé los backups de mi infraestructura Docker usando rsync y cron. Es simple, eficiente y funciona.

La estrategia

Mi enfoque es straightforward:

  1. rsync para sincronizar incrementalmente solo lo que cambió
  2. cron para automatizar la ejecución diaria
  3. Un disco externo USB como destino de backup
  4. Retención de múltiples snapshots para recuperación granular

Esto no es backup en cloud. Es backup local, rápido y bajo mi control.

Configuración paso a paso

1. Preparar el almacenamiento

Conecté un disco USB y lo monté en /mnt/backup. Verificá que esté disponible:

lsblk
mount | grep backup

2. Script de backup

Creé /usr/local/bin/docker-backup.sh:

#!/bin/bash

BACKUP_DEST="/mnt/backup"
DOCKER_DATA="/var/lib/docker"
COMPOSE_DIR="/home/user/docker-compose"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_PATH="$BACKUP_DEST/backups/$TIMESTAMP"

# Crear directorio de backup
mkdir -p "$BACKUP_PATH"

# Backup de volúmenes Docker
echo "[$(date)] Iniciando backup de Docker volumes..."
rsync -av --delete "$DOCKER_DATA/volumes/" "$BACKUP_PATH/volumes/" >> /var/log/docker-backup.log 2>&1

# Backup de configuraciones docker-compose
echo "[$(date)] Iniciando backup de docker-compose..."
rsync -av "$COMPOSE_DIR/" "$BACKUP_PATH/compose/" >> /var/log/docker-backup.log 2>&1

# Backup incremental de datos de aplicaciones
echo "[$(date)] Iniciando backup de datos..."
rsync -av --delete "/home/user/app-data/" "$BACKUP_PATH/app-data/" >> /var/log/docker-backup.log 2>&1

# Limpiar backups más antiguos (mantener 7 últimos)
echo "[$(date)] Limpiando backups antiguos..."
ls -t "$BACKUP_DEST/backups" | tail -n +8 | xargs -I {} rm -rf "$BACKUP_DEST/backups/{}"

echo "[$(date)] Backup completado" >> /var/log/docker-backup.log

Hacerlo ejecutable:

chmod +x /usr/local/bin/docker-backup.sh

3. Configurar cron

Edité la tabla cron del usuario root:

sudo crontab -e

Agregué esta línea para ejecutar a las 2 AM todos los días:

0 2 * * * /usr/local/bin/docker-backup.sh

Para verificar que está registrado:

sudo crontab -l

4. Monitoreo

Creé un segundo script para alertarme si algo falla. En /usr/local/bin/check-backup.sh:

#!/bin/bash

LAST_BACKUP=$(ls -t /mnt/backup/backups | head -1)
BACKUP_TIME=$(date -d "$(stat -c %y /mnt/backup/backups/$LAST_BACKUP | cut -d' ' -f1)" +%s)
CURRENT_TIME=$(date +%s)
DIFF=$((($CURRENT_TIME - $BACKUP_TIME) / 3600))

if [ $DIFF -gt 25 ]; then
    echo "ALERTA: No hay backup desde hace $DIFF horas"
else
    echo "Último backup: $DIFF horas atrás - OK"
fi

Lo ejecuto manualmente cada semana o via cron si quiero:

chmod +x /usr/local/bin/check-backup.sh
/usr/local/bin/check-backup.sh

Consideraciones importantes

Espacio en disco: rsync con --delete sincroniza exactamente el origen. Reviso que el destino tenga al menos 1.5x el tamaño de los datos Docker.

Permisos: El script corre como root, así que puede acceder a /var/lib/docker. Si usas un usuario regular, necesitarás permisos especiales.

Pruebas: Una vez al mes simulo una recuperación restaurando un archivo aleatorio en una máquina de prueba. Un backup que nunca se probó no existe.

Cifrado: Mi disco USB está en casa conmigo, así que no lo cifro. Si lo mantuvieras en otro lugar, considera --backup-dir con sincronización a un destino cifrado.

Resultado

Ahora duermo mejor. Cada noche a las 2 AM, Docker, las configuraciones y los datos se sincronizan automáticamente. Si el servidor muere, recupero todo en 30 minutos.

La clave es: automatización simple, verificación manual. No esperes a que falle algo para probar tu backup.


Equipamiento recomendado

Enlaces de afiliado. Sin coste extra para ti.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *