Ir al contenido

Automatizar backups incrementales de volúmenes Docker con rsync, validación y alertas por Telegram

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.

El problema
#

Hace tiempo me pasó: un volumen Docker corrupto y sin backup limpio. Desde entonces, automatizo backups incrementales de mis volúmenes críticos. Te muestro cómo lo hago.

Requisitos
#

  • Servidor Docker en Linux (Debian/Ubuntu)
  • Acceso SSH a almacenamiento remoto (NAS, VPS, etc.)
  • rsync instalado
  • Bot de Telegram configurado
  • Permisos de sudo o acceso directo a volúmenes

Paso 1: Preparar el script de backup
#

Creo /opt/docker-backup/backup.sh:

#!/bin/bash

BACKUP_SOURCE="/var/lib/docker/volumes"
BACKUP_DEST="user@remote-storage:/backups/docker-volumes"
LOG_FILE="/var/log/docker-backup.log"
CHECKSUM_FILE="/var/log/docker-backup.checksum"
TELEGRAM_TOKEN="YOUR_BOT_TOKEN"
TELEGRAM_CHAT="YOUR_CHAT_ID"

# Función para enviar alertas por Telegram
send_alert() {
    local message=$1
    local status=$2
    
    if [ "$status" = "error" ]; then
        curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \
            -d chat_id="${TELEGRAM_CHAT}" \
            -d text="❌ Docker Backup Error: ${message}"
    else
        curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_TOKEN}/sendMessage" \
            -d chat_id="${TELEGRAM_CHAT}" \
            -d text="✅ Docker Backup: ${message}"
    fi
}

# Crear directorio de log si no existe
mkdir -p $(dirname "$LOG_FILE")

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Iniciando backup incremental" >> "$LOG_FILE"

# Ejecutar rsync incremental
rsync -av --delete \
    --backup-dir="/backups/docker-volumes/daily-$(date +%Y%m%d)" \
    "$BACKUP_SOURCE/" "$BACKUP_DEST/" >> "$LOG_FILE" 2>&1

if [ $? -eq 0 ]; then
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup completado exitosamente" >> "$LOG_FILE"
    BACKUP_STATUS="exitoso"
else
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR en backup" >> "$LOG_FILE"
    send_alert "Fallo en transferencia rsync" "error"
    exit 1
fi

Paso 2: Validación de integridad
#

Agrego a backup.sh:

# Generar checksum local
find "$BACKUP_SOURCE" -type f -exec md5sum {} \; | sort > /tmp/local.checksum

# Verificar checksum remoto
ssh user@remote-storage "find /backups/docker-volumes -type f -exec md5sum {} \; | sort > /tmp/remote.checksum"

# Comparar
rsync --checksum "$BACKUP_SOURCE/" "$BACKUP_DEST/" --dry-run > /tmp/verify.log 2>&1

DIFF_COUNT=$(grep -c "would be transferred" /tmp/verify.log)

if [ "$DIFF_COUNT" -gt 0 ]; then
    send_alert "Advertencia: ${DIFF_COUNT} archivos no sincronizados" "error"
else
    send_alert "Integridad verificada: $(du -sh $BACKUP_SOURCE | cut -f1)" "ok"
fi

Paso 3: Configurar cron
#

Edito /etc/cron.d/docker-backup:

# Backup completo cada domingo a las 2 AM
0 2 * * 0 root /opt/docker-backup/backup.sh

# Backup incremental diario a las 3 AM
0 3 * * 1-6 root /opt/docker-backup/backup.sh

# Limpieza de backups antiguos (más de 30 días) cada viernes
0 4 * * 5 root find /backups/docker-volumes/daily-* -mtime +30 -delete

Paso 4: Configurar Telegram
#

Creo un bot en BotFather y obtengo el token. Luego:

# Probar conexión
curl -s -X POST "https://api.telegram.org/botTOKEN/sendMessage" \
    -d chat_id="CHAT_ID" \
    -d text="Test de conexión"

Paso 5: Permisos y prueba
#

chmod 750 /opt/docker-backup/backup.sh
chmod 640 /etc/cron.d/docker-backup

# Ejecutar manualmente para verificar
/opt/docker-backup/backup.sh

En producción
#

Reviso logs semanalmente:

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

He detectado problemas temprano gracias a las alertas de Telegram. El script se ejecuta sin intervención manual y rsync solo transfiere lo que cambió. Con esto dormía más tranquilo.