Ir al contenido

Automatizar backups incrementales de volúmenes Docker a almacenamiento remoto con rsync y cron

Rogelio Guerra Riverón
Autor
Rogelio Guerra Riverón
Construyendo mi propia infraestructura web desde cero. Aquí documento cada paso: servidores, redes, contenedores y lo que vaya surgiendo.

Tenía un problema real: mis datos en volúmenes Docker estaban solo en el servidor local. Un fallo de disco y perdía todo. Necesitaba backups automáticos, incrementales y notificaciones cuando algo fallara. Aquí está lo que implementé.

El plan
#

Usar rsync para copiar solo lo que cambió, ejecutarlo cada noche con cron, y recibir un email si algo falla. Simple y sin dependencias raras.

Paso 1: Preparar el almacenamiento remoto
#

Acceso SSH al servidor remoto configurado sin contraseña (con claves). En mi caso, un NAS en la red.

ssh-keygen -t ed25519 -f ~/.ssh/backup_key -N ""
ssh-copy-id -i ~/.ssh/backup_key user@nas.local

Crear el directorio destino:

ssh -i ~/.ssh/backup_key user@nas.local mkdir -p /backups/docker-volumes

Paso 2: Crear el script de backup
#

Archivo: /opt/backup/backup-docker-volumes.sh

#!/bin/bash

BACKUP_HOST="user@nas.local"
BACKUP_PATH="/backups/docker-volumes"
SSH_KEY="/root/.ssh/backup_key"
DOCKER_VOLUMES_PATH="/var/lib/docker/volumes"
LOG_FILE="/var/log/docker-backup.log"
EMAIL="admin@example.local"

# Función para registrar
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}

# Función para enviar alertas
send_alert() {
    local subject="$1"
    local message="$2"
    echo "$message" | mail -s "$subject" "$EMAIL"
}

log "Iniciando backup de volúmenes Docker"

# Listar y respaldar cada volumen
for volume in $(docker volume ls --quiet); do
    VOLUME_PATH="$DOCKER_VOLUMES_PATH/$volume/_data"
    
    if [ ! -d "$VOLUME_PATH" ]; then
        log "ADVERTENCIA: No se encontró $VOLUME_PATH"
        continue
    fi
    
    log "Respaldando volumen: $volume"
    
    rsync -avz --delete \
        -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no" \
        "$VOLUME_PATH/" \
        "$BACKUP_HOST:$BACKUP_PATH/$volume/" \
        >> "$LOG_FILE" 2>&1
    
    if [ $? -eq 0 ]; then
        log "✓ Volumen $volume respaldado correctamente"
    else
        log "✗ ERROR respaldando $volume"
        send_alert "FALLO: Backup Docker - $volume" \
            "El backup del volumen $volume falló. Revisa $LOG_FILE"
        exit 1
    fi
done

log "Backup completado"
send_alert "OK: Backup Docker completado" "Todos los volúmenes se respaldaron correctamente en $(date)"

Dar permisos:

chmod 755 /opt/backup/backup-docker-volumes.sh

Paso 3: Configurar cron
#

Abre el crontab root:

crontab -e

Añade esta línea para ejecutar cada noche a las 3 AM:

0 3 * * * /opt/backup/backup-docker-volumes.sh

Paso 4: Configurar el correo
#

Instala un MTA ligero. En Debian/Ubuntu:

apt-get install msmtp msmtp-mta

Archivo de configuración: ~/.msmtprc

defaults
auth on
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt

account gmail
host smtp.gmail.com
port 587
from docker-backup@example.local
user tu_correo@gmail.com
password tu_contraseña_app

account default : gmail

Permisos restringidos:

chmod 600 ~/.msmtprc

Paso 5: Prueba
#

/opt/backup/backup-docker-volumes.sh

Verifica el log:

tail -f /var/log/docker-backup.log

Consideraciones reales
#

Espacio: Los primeros backups pesan. Monitorea el almacenamiento remoto.

Ancho de banda: rsync es eficiente, pero con volúmenes grandes nocturno es mejor.

Seguridad: La clave SSH sin contraseña funciona, pero está en el servidor. Usa permisos restrictivos (600 en la clave).

Rotación: Después de 30 días, los incrementales se acumulan. Considera crear snapshots mensuales completos.

Verificación: Una vez al mes, restaura algo de verdad. Un backup sin testar es un backup que no funciona.

He estado usando esto 8 meses. Solo ha fallado por timeout SSH (solución: aumenté el timeout en rsync). Los emails de confirmación diaria me dan paz mental.