Ir al contenido

Automatizar backups incrementales de 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
#

Tenía varios contenedores Docker corriendo servicios críticos en mi servidor doméstico. La idea de perder datos por un fallo de disco me mantenía despierto. Necesitaba una solución que:

  • Fuera incremental (no copiar todo cada vez)
  • Se ejecutara automáticamente sin intervención
  • Permitiera rotación de copias antiguas
  • Guardara los datos en almacenamiento remoto

Después de probar varias opciones, restic fue la respuesta. Es rápido, eficiente y se integra bien con cron.

Instalación de restic
#

Lo primero es instalar restic en el servidor:

curl -sL https://api.github.com/repos/restic/restic/releases/latest | grep -oP '"browser_download_url": "\K.*linux_amd64\.bz2' | head -1 | xargs wget -O - | bunzip2 > /usr/local/bin/restic
chmod +x /usr/local/bin/restic
restic version

También necesito jq para procesar JSON en los scripts:

apt-get install jq

Configurar almacenamiento remoto
#

Usé un servidor SFTP remoto, pero restic soporta S3, B2, Google Cloud, etc.

Primero creo el repositorio:

export RESTIC_REPOSITORY="sftp:usuario@servidor.remoto:/ruta/backups/docker"
export RESTIC_PASSWORD="contraseña_super_segura"
restic init

Guardo las credenciales en un archivo protegido:

cat > /root/.restic_env << 'EOF'
export RESTIC_REPOSITORY="sftp:usuario@servidor.remoto:/ruta/backups/docker"
export RESTIC_PASSWORD="contraseña_super_segura"
export RESTIC_CACHE_DIR="/var/cache/restic"
EOF

chmod 600 /root/.restic_env

Script de backup
#

Creo el script principal en /usr/local/bin/docker-backup.sh:

#!/bin/bash

source /root/.restic_env

# Exportar volúmenes de contenedores específicos
CONTAINERS=("contenedor1" "contenedor2" "contenedor3")
BACKUP_DIR="/tmp/docker-backup"

mkdir -p "$BACKUP_DIR"

for container in "${CONTAINERS[@]}"; do
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] Exportando $container..."
    docker export "$container" | gzip > "$BACKUP_DIR/$container.tar.gz"
done

# Backup de directorios de volúmenes
echo "[$(date +'%Y-%m-%d %H:%M:%S')] Iniciando backup con restic..."
restic backup "$BACKUP_DIR" \
    --tag "docker-backup" \
    --tag "$(date +'%Y-%m-%d')" \
    --verbose

if [ $? -eq 0 ]; then
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] Backup exitoso"
    rm -rf "$BACKUP_DIR"
else
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] Error en backup" >&2
    exit 1
fi

Lo hago ejecutable:

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

Script de rotación
#

Creo otro script para limpiar backups antiguos en /usr/local/bin/docker-backup-prune.sh:

#!/bin/bash

source /root/.restic_env

echo "[$(date +'%Y-%m-%d %H:%M:%S')] Iniciando limpieza de backups antiguos..."

# Mantener últimos 30 backups diarios y 12 mensuales
restic forget \
    --keep-daily 30 \
    --keep-monthly 12 \
    --keep-yearly 2 \
    --tag "docker-backup" \
    --prune \
    --verbose

echo "[$(date +'%Y-%m-%d %H:%M:%S')] Limpieza completada"
chmod +x /usr/local/bin/docker-backup-prune.sh

Configurar cron
#

Edito la crontab del root:

crontab -e

Agrego las siguientes líneas:

# Backup diario a las 2 AM
0 2 * * * /usr/local/bin/docker-backup.sh >> /var/log/docker-backup.log 2>&1

# Rotación de backups cada domingo a las 3 AM
0 3 * * 0 /usr/local/bin/docker-backup-prune.sh >> /var/log/docker-backup.log 2>&1

Monitoreo
#

Para saber qué está pasando, reviso los logs regularmente:

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

También puedo verificar el estado del repositorio:

source /root/.restic_env
restic snapshots
restic stats

Resultado
#

Después de una semana funcionando, tengo:

  • Backups incrementales diarios sin intervención manual
  • 30 días de historiales disponibles
  • Rotación automática de copias antiguas
  • Datos replicados en servidor remoto seguro

Esto me quitó la preocupación. Los contenedores están protegidos.