El problema#
Tenía varios contenedores Docker con datos importantes: bases de datos, archivos de configuración, datos de aplicaciones. Necesitaba backups automáticos, incrementales y con retención inteligente. No quería gastar mucho en almacenamiento externo.
La solución: restic + S3. Restic es pequeño, eficiente y maneja incrementales nativamente. S3 es barato y confiable.
Setup inicial#
Primero instalé restic en el host:
curl -b /tmp/restic.bz2 -L https://github.com/restic/restic/releases/download/v0.16.0/restic_0.16.0_linux_amd64.bz2
cd /tmp && bunzip2 restic.bz2 && mv restic /usr/local/bin/
chmod +x /usr/local/bin/resticCreé credenciales de AWS IAM con permisos solo para S3:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketVersioning",
"s3:ListBucketVersions"
],
"Resource": "arn:aws:s3:::mi-bucket-backups"
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::mi-bucket-backups/*"
}
]
}Inicializar repositorio restic#
export AWS_ACCESS_KEY_ID="tu_access_key"
export AWS_SECRET_ACCESS_KEY="tu_secret_key"
export RESTIC_PASSWORD="contraseña_muy_segura"
restic -r s3:s3.amazonaws.com/mi-bucket-backups initGuardé estas variables en /etc/restic/env con permisos 600.
Script de backup#
Creé /usr/local/bin/backup-docker-volumes.sh:
#!/bin/bash
source /etc/restic/env
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/restic-backup-${TIMESTAMP}.log"
# Array de volúmenes a respaldar
VOLUMES=(
"postgres_data"
"nginx_config"
"app_data"
)
# Montar volúmenes temporalmente
MOUNT_POINT="/mnt/backup_volumes"
mkdir -p ${MOUNT_POINT}
for VOLUME in "${VOLUMES[@]}"; do
VOLUME_PATH="${MOUNT_POINT}/${VOLUME}"
mkdir -p ${VOLUME_PATH}
docker run --rm -v ${VOLUME}:/data -v ${MOUNT_POINT}:/mnt alpine \
cp -r /data/* /mnt/${VOLUME}/ 2>/dev/null || true
done
# Ejecutar backup incremental
restic -r s3:s3.amazonaws.com/mi-bucket-backups backup ${MOUNT_POINT} \
--tag docker-volumes \
--tag $(date +%Y-%m-%d) \
>> ${LOG_FILE} 2>&1
BACKUP_STATUS=$?
# Limpiar
rm -rf ${MOUNT_POINT}
# Rotación: mantener últimos 30 días diarios, 12 meses semanales
restic -r s3:s3.amazonaws.com/mi-bucket-backups forget \
--keep-daily 30 \
--keep-weekly 12 \
--keep-monthly 6 \
--prune \
>> ${LOG_FILE} 2>&1
if [ $BACKUP_STATUS -eq 0 ]; then
echo "Backup exitoso" >> ${LOG_FILE}
exit 0
else
echo "Error en backup" >> ${LOG_FILE}
exit 1
fiLo hice ejecutable:
chmod +x /usr/local/bin/backup-docker-volumes.shAutomatizar con systemd#
Creé /etc/systemd/system/docker-backup.service:
[Unit]
Description=Docker Volumes Backup to S3
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup-docker-volumes.sh
StandardOutput=journal
StandardError=journalY el timer en /etc/systemd/system/docker-backup.timer:
[Unit]
Description=Daily Docker Backup Timer
[Timer]
OnCalendar=daily
OnCalendar=*-*-* 02:00:00
Persistent=true
[Install]
WantedBy=timers.targetActivé el timer:
systemctl daemon-reload
systemctl enable docker-backup.timer
systemctl start docker-backup.timerVerificación y monitoreo#
Para ver el estado:
systemctl status docker-backup.timer
journalctl -u docker-backup.service -fPara listar snapshots:
restic -r s3:s3.amazonaws.com/mi-bucket-backups snapshotsPara restaurar un volumen específico:
restic -r s3:s3.amazonaws.com/mi-bucket-backups restore latest \
--target /tmp/restore \
--path /mnt/backup_volumes/postgres_dataResultado final#
Los backups corren automáticamente cada madrugada. Restic comprime y deduplica, así que el almacenamiento en S3 es mínimo. La rotación automática mantiene 30 días de backups diarios sin acumular basura.
Llevó una tarde configurarlo, pero ahora duermo tranquilo.