Lo que vas a construir
Scripts para hacer backup y restore de volúmenes Docker. Protegerás tus datos de PostgreSQL, Redis, y cualquier otro servicio.
Al terminar tendrás:
- Script de backup que crea archivos .tar.gz
- Script de restore para recuperar datos
- Backup automático con cron
Paso 1: Crea un volumen de prueba
# Crear volumen
docker volume create test_data
# Crear contenedor con datos
docker run --rm -v test_data:/data alpine sh -c "
echo 'Datos importantes' > /data/archivo.txt
echo 'Más datos' > /data/config.json
mkdir /data/subdir
echo 'Anidado' > /data/subdir/nested.txt
"
# Verificar contenido
docker run --rm -v test_data:/data alpine ls -la /data
Paso 2: Backup manual
# Backup a archivo .tar.gz
docker run --rm \
-v test_data:/source:ro \
-v $(pwd):/backup \
alpine tar czf /backup/test_data_backup.tar.gz -C /source .
# Verificar
ls -lh test_data_backup.tar.gz
tar tzf test_data_backup.tar.gz
Paso 3: Script de backup
Crea backup-volume.sh:
#!/bin/bash
# backup-volume.sh - Backup de volumen Docker
VOLUME_NAME=${1:?Uso: ./backup-volume.sh NOMBRE_VOLUMEN}
BACKUP_DIR=${2:-./backups}
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/${VOLUME_NAME}_${TIMESTAMP}.tar.gz"
mkdir -p "$BACKUP_DIR"
echo "Haciendo backup de '$VOLUME_NAME' a '$BACKUP_FILE'..."
docker run --rm \
-v "$VOLUME_NAME":/source:ro \
-v "$BACKUP_DIR":/backup \
alpine tar czf "/backup/${VOLUME_NAME}_${TIMESTAMP}.tar.gz" -C /source .
if [ $? -eq 0 ]; then
echo "✅ Backup completado: $BACKUP_FILE"
echo " Tamaño: $(ls -lh "$BACKUP_FILE" | awk '{print $5}')"
else
echo "❌ Error en backup"
exit 1
fi
chmod +x backup-volume.sh
./backup-volume.sh test_data ./backups
Paso 4: Script de restore
Crea restore-volume.sh:
#!/bin/bash
# restore-volume.sh - Restaurar volumen Docker
BACKUP_FILE=${1:?Uso: ./restore-volume.sh ARCHIVO.tar.gz NOMBRE_VOLUMEN}
VOLUME_NAME=${2:?Uso: ./restore-volume.sh ARCHIVO.tar.gz NOMBRE_VOLUMEN}
if [ ! -f "$BACKUP_FILE" ]; then
echo "❌ Archivo no encontrado: $BACKUP_FILE"
exit 1
fi
echo "⚠️ Esto sobrescribirá el volumen '$VOLUME_NAME'"
read -p "¿Continuar? (y/N) " confirm
[ "$confirm" != "y" ] && exit 0
# Crear volumen si no existe
docker volume create "$VOLUME_NAME" 2>/dev/null
echo "Restaurando '$BACKUP_FILE' a '$VOLUME_NAME'..."
docker run --rm \
-v "$VOLUME_NAME":/target \
-v "$(pwd)":/backup \
alpine sh -c "rm -rf /target/* && tar xzf /backup/$(basename $BACKUP_FILE) -C /target"
if [ $? -eq 0 ]; then
echo "✅ Restore completado"
else
echo "❌ Error en restore"
exit 1
fi
Paso 5: Probar restore
# Eliminar volumen original
docker volume rm test_data
# Restaurar desde backup
./restore-volume.sh backups/test_data_*.tar.gz test_data_restored
# Verificar
docker run --rm -v test_data_restored:/data alpine cat /data/archivo.txt
Paso 6: Backup de PostgreSQL (mejor práctica)
Para bases de datos, usa pg_dump antes de comprimir:
#!/bin/bash
# backup-postgres.sh
CONTAINER=${1:-postgres}
BACKUP_DIR=./backups
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
docker exec $CONTAINER pg_dumpall -U postgres | gzip > "$BACKUP_DIR/postgres_$TIMESTAMP.sql.gz"
echo "✅ Backup: $BACKUP_DIR/postgres_$TIMESTAMP.sql.gz"
Restore:
gunzip -c backups/postgres_*.sql.gz | docker exec -i postgres psql -U postgres
Paso 7: Backup automático (cron)
# Editar crontab
crontab -e
# Backup diario a las 3am
0 3 * * * /opt/scripts/backup-volume.sh postgres_data /opt/backups >> /var/log/backup.log 2>&1
# Backup cada 6 horas
0 */6 * * * /opt/scripts/backup-postgres.sh postgres >> /var/log/backup.log 2>&1
Paso 8: Rotación de backups
Mantén solo los últimos N backups:
# Eliminar backups de más de 7 días
find /opt/backups -name "*.tar.gz" -mtime +7 -delete
# Mantener solo los últimos 5
ls -t /opt/backups/*.tar.gz | tail -n +6 | xargs rm -f
Script completo con rotación
#!/bin/bash
# backup-with-rotation.sh
VOLUME=$1
BACKUP_DIR=/opt/backups
KEEP=7
./backup-volume.sh "$VOLUME" "$BACKUP_DIR"
# Eliminar viejos
ls -t "$BACKUP_DIR/${VOLUME}_"*.tar.gz 2>/dev/null | tail -n +$((KEEP+1)) | xargs rm -f
echo "Backups actuales:"
ls -lh "$BACKUP_DIR/${VOLUME}_"*.tar.gz
Verificar integridad
# Verificar que el tar es válido
tar tzf backup.tar.gz > /dev/null && echo "✅ Archivo válido" || echo "❌ Corrupto"
# Ver contenido sin extraer
tar tzf backup.tar.gz | head -20