Ir al contenido

Automatizar backups incrementales de volúmenes Docker con restic 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.

El problema
#

Después de perder datos por un fallo de almacenamiento, aprendí que los contenedores Docker son efímeros. Los volúmenes que albergan bases de datos, configuraciones y archivos importantes necesitan protección. Backups manuales no escalan. Necesitaba algo automatizado, eficiente y verificable.

Elegí restic porque hace backups incrementales (solo guarda cambios), es agnóstico del destino (local, S3, B2, etc.) y verifica integridad con hash. Combinado con cron, tengo una solución sólida.

Instalación
#

En mi servidor Debian, instalo restic:

sudo apt-get update && sudo apt-get install -y restic

Para backups locales, creo el directorio de destino:

sudo mkdir -p /mnt/backup-storage
sudo chmod 700 /mnt/backup-storage

Si usas almacenamiento remoto (recomendado), configura credenciales. Yo uso un bucket S3 local con Minio, pero la sintaxis es similar.

Inicializar repositorio
#

Restic necesita un repositorio inicializado. Lo hago una sola vez:

restic -r /mnt/backup-storage init

Me pide una contraseña. La guardo en un gestor seguro. Sin ella, los backups son inútiles.

Script de backup
#

Creo /usr/local/bin/backup-docker-volumes.sh:

#!/bin/bash

# Variables
RESTIC_REPO="/mnt/backup-storage"
RESTIC_PASSWORD="tu_contraseña_aqui"
LOG_FILE="/var/log/docker-backup.log"
DOCKER_VOLUMES_PATH="/var/lib/docker/volumes"

# Timestamp
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

# Exportar variables para restic
export RESTIC_REPOSITORY="$RESTIC_REPO"
export RESTIC_PASSWORD="$RESTIC_PASSWORD"

# Función de logging
log() {
    echo "[$TIMESTAMP] $1" >> "$LOG_FILE"
}

log "=== Iniciando backup de volúmenes Docker ==="

# Backup de volúmenes
restic backup "$DOCKER_VOLUMES_PATH" \
    --tag docker-volumes \
    --exclude='lost+found' \
    --exclude='.git' \
    >> "$LOG_FILE" 2>&1

if [ $? -eq 0 ]; then
    log "✓ Backup completado exitosamente"
else
    log "✗ Error durante el backup"
    exit 1
fi

# Limpiar snapshots antiguos (mantener últimos 30 días)
restic forget --keep-daily 30 --prune >> "$LOG_FILE" 2>&1

log "=== Limpieza de snapshots antiguos completada ==="

# Verificar integridad
restic check >> "$LOG_FILE" 2>&1

if [ $? -eq 0 ]; then
    log "✓ Verificación de integridad exitosa"
else
    log "✗ Error en verificación de integridad"
    exit 1
fi

Hago el script ejecutable:

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

Programar con cron
#

Edito la tabla cron del root:

sudo crontab -e

Agrego esta línea para ejecutar backups diariamente a las 2 AM:

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

Para backups cada 6 horas:

0 */6 * * * /usr/local/bin/backup-docker-volumes.sh

Verifico que se ejecute:

sudo grep CRON /var/log/syslog | tail -5

Recuperación ante desastres
#

Cuando necesito restaurar:

# Listar snapshots disponibles
restic snapshots

# Restaurar un snapshot específico
restic restore [snapshot-id] --target /mnt/restore-point

Si un contenedor se corrompió, detengo el stack, restauro el volumen y reinicio:

docker-compose down
restic restore [snapshot-id] --target /var/lib/docker/volumes/mi-volumen
docker-compose up -d

Buenas prácticas aprendidas
#

  • Nunca guardes la contraseña en texto plano en cron. Yo uso un archivo /root/.restic-pass con permisos 600.
  • Monitorea los logs. Configura alertas si los backups fallan.
  • Prueba restauraciones regularmente. Un backup no probado es un backup que no funciona.
  • Guarda backups fuera de tu servidor. La redundancia local no te protege de hardware fallido.
  • Cifra los backups si los envías a cloud. Restic lo hace por defecto.

Resultado
#

Ahora duermo tranquilo. Mis volúmenes Docker se respaldan cada 6 horas, solo guardo cambios (restic es eficiente), y puedo recuperar cualquier cosa en minutos. El destino de mis backups es un NAS en otra ubicación, así que aunque el servidor explote, mis datos están seguros.