El problema real#
Tenía PostgreSQL corriendo en Docker y los backups manuales no escalan. Necesitaba algo automático, que verificara que los datos estuvieran bien y que limpiara lo viejo sin intervención.
La solución que implementé#
Creé un script bash que:
- Genera backups incrementales en formato custom (comprimido)
- Verifica la integridad de cada copia
- Mantiene solo los últimos N backups
- Corre vía cron en horarios específicos
Paso 1: Preparar el almacenamiento externo#
Monté un disco externo en /mnt/backups-postgres/:
sudo mkdir -p /mnt/backups-postgres
sudo chown $USER:$USER /mnt/backups-postgres
chmod 700 /mnt/backups-postgresCada día un subdirectorio separado:
mkdir -p /mnt/backups-postgres/$(date +%Y-%m-%d)Paso 2: El script de backup#
Creé /home/rogelio/scripts/backup-postgres.sh:
#!/bin/bash
BACKUP_DIR="/mnt/backups-postgres/$(date +%Y-%m-%d)"
CONTAINER_NAME="postgres-prod"
DB_USER="postgres"
TIMESTAMP=$(date +%H-%M-%S)
BACKUP_FILE="$BACKUP_DIR/backup-$TIMESTAMP.custom"
LOG_FILE="$BACKUP_DIR/backup-$TIMESTAMP.log"
# Crear directorio del día
mkdir -p "$BACKUP_DIR"
# Ejecutar dump incrementa (custom format)
docker exec $CONTAINER_NAME pg_dump \
-U $DB_USER \
-Fc \
--verbose \
--compress=9 \
postgres > "$BACKUP_FILE" 2> "$LOG_FILE"
if [ $? -eq 0 ]; then
echo "✓ Backup exitoso: $BACKUP_FILE" >> "$LOG_FILE"
# Verificación de integridad
docker exec $CONTAINER_NAME pg_restore \
-U $DB_USER \
--list "$BACKUP_FILE" > /dev/null 2>&1
if [ $? -eq 0 ]; then
echo "✓ Verificación OK" >> "$LOG_FILE"
echo "$(date '+%Y-%m-%d %H:%M:%S') - Backup exitoso y verificado" >> "$BACKUP_DIR/resumen.log"
else
echo "✗ Verificación fallida" >> "$LOG_FILE"
exit 1
fi
else
echo "✗ Error en backup" >> "$LOG_FILE"
exit 1
fiPaso 3: Rotación de backups antiguos#
Agregué al script una función de limpieza:
# Mantener solo 7 días de backups
RETENTION_DAYS=7
find /mnt/backups-postgres -maxdepth 1 -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \; 2>/dev/null
echo "Rotación completada: directorios mayores a $RETENTION_DAYS días eliminados"Paso 4: Automatizar con cron#
crontab -eAgregué estas líneas:
# Backup cada 6 horas
0 0,6,12,18 * * * /home/rogelio/scripts/backup-postgres.sh
# Verificación semanal de integridad
0 3 * * 0 /home/rogelio/scripts/verify-backups.shPaso 5: Script de verificación adicional#
Creé /home/rogelio/scripts/verify-backups.sh para validar todos los backups de una vez:
#!/bin/bash
BACKUP_DIR="/mnt/backups-postgres"
FAILED=0
for backup_file in $(find $BACKUP_DIR -name "*.custom" -type f); do
docker exec postgres-prod pg_restore \
-U postgres \
--list "$backup_file" > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "✗ Fallo verificación: $backup_file"
FAILED=$((FAILED + 1))
fi
done
if [ $FAILED -eq 0 ]; then
echo "✓ Todos los backups verificados correctamente"
else
echo "✗ $FAILED backups fallaron verificación"
# Aquí podrías enviar alerta por correo
exit 1
fiMonitoreo real#
Los logs quedan en cada directorio. Reviso el resumen:
tail -f /mnt/backups-postgres/$(date +%Y-%m-%d)/resumen.logLo que aprendí#
- El formato
customes mejor que SQL plano: comprime más y permite restaurar tablas específicas - Validar con
pg_restore --listes rápido y confiable - No confíes solo en el cron: agrega logs para verificar que corre
- El almacenamiento externo montado directamente es más rápido que NAS
Llevo 6 meses con esto sin problemas. Los backups incrementales con rotación automática funcionan sin intervención y la verificación de integridad te da tranquilidad real.