Problema
En entornos donde Docker se usa para ejecutar bases de datos, aplicaciones con estado o servicios que generan datos en tiempo real, los volúmenes son el único punto persistente. Cuando el host falla, se pierde la única copia de esos datos si no se cuenta con un mecanismo de respaldo. El patrón recurrente es la falta de una estrategia de backup/restore que:
- Capture el estado de los volúmenes sin detener los contenedores.
- Permita retener copias según políticas (diarias, semanales, mensuales).
- Almacene los archivos en un backend externo (S3, Azure Blob, etc.).
- Ofrezca una vía de restauración rápida y verificable.
Sin una solución estructurada, los administradores terminan improvisando scripts ad‑hoc que se rompen con actualizaciones de Docker, cambios de driver de storage o simplemente por falta de pruebas de restauración.
Causa
Los fallos habituales provienen de tres grupos de causas:
- Acceso concurrente al volumen – Intentar copiar un volumen mientras el contenedor escribe genera archivos corruptos o inconsistentes. La mayoría de los scripts usan
docker cpotardirectamente sobre el directorio montado, lo que no garantiza atomicidad. - Falta de integración con backends de objetos – Copiar a disco local y luego mover a S3 con
aws s3 cpfunciona, pero no gestiona versiones ni expiración automática. Cuando la política de retención cambia, los archivos quedan dispersos y difíciles de limpiar. - Ausencia de metadatos de backup – Sin registrar qué contenedor, qué volumen y qué punto de tiempo corresponde a cada archivo, la restauración se vuelve un proceso de prueba y error. Los sistemas que solo guardan un tarball sin etiquetas de versión terminan restaurando datos obsoletos.
Solución
Una solución reutilizable se basa en tres pilares:
-
Snapshot consistente del volumen
Utiliza la funcionalidad dedocker run --rm -v <volumen>:/data alpine tar czf - -C /data .dentro de un contenedor temporal. El contenedor se ejecuta en modo read‑only y no interfiere con el proceso principal. Para drivers que soportan snapshots (btrfs, ZFS, overlay2 condocker commit), aprovecha la API nativa antes de empaquetar. -
Orquestación de backups con una herramienta open‑source
Plataformas como Portabase, Restic o BorgBackup manejan la compresión, cifrado y envío a múltiples backends. La configuración típica incluye:- Definir un “data source” que apunte al volumen.
- Establecer políticas GFS (Grandfather‑Father‑Son) o retención basada en número de copias.
- Configurar credenciales para S3, Azure Blob o Google Cloud Storage.
-
Registro de metadatos y versionado
Cada backup genera un manifiesto JSON con campos:volume_name,container_id,timestamp,checksum. El manifiesto se almacena junto al archivo tarball en el mismo bucket, facilitando búsquedas y validaciones posteriores.
Paso a paso (ejemplo con Portabase)
- Crear un job de backup en
portabase.yamlque apunte al volumenmydata. - Programar la ejecución mediante cron o el scheduler interno de la herramienta.
- Activar la política de retención GFS: 7 diarios, 4 semanales, 12 mensuales.
- Habilitar notificaciones (Slack/Discord) para alertas de fallos.
El mismo flujo se adapta a Restic cambiando la definición del repositorio y el comando restic backup /path/to/volume.
Cuándo aplicar esta solución
Aplica cuando:
- Los contenedores manejan datos críticos (bases de datos, logs, archivos de usuario).
- Necesitas cumplir con SLA de recuperación (RTO/RPO) sin detener los servicios.
- Se requiere almacenar backups en la nube o en un NAS externo.
No es necesario si:
- Los volúmenes son efímeros y pueden recrearse sin pérdida de información.
- Sólo se usa Docker en entornos de desarrollo local sin requisitos de retención.
Código
# 1. Crear snapshot temporal y empaquetar
docker run --rm \
-v mydata:/data \
-v $(pwd)/backups:/backup \
alpine \
sh -c "tar czf /backup/mydata_$(date +%Y%m%d%H%M%S).tar.gz -C /data ."
# 2. Subir a S3 usando awscli (asumiendo que aws credentials están configuradas)
aws s3 cp backups/ s3://my-backup-bucket/docker-volumes/ --recursive --storage-class STANDARD_IA
# 3. Generar manifiesto JSON
cat <<EOF > backups/manifest_$(date +%Y%m%d%H%M%S).json
{
"volume": "mydata",
"container": "$(docker ps -q -f \"volume=mydata\")",
"timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
"file": "mydata_$(date +%Y%m%d%H%M%S).tar.gz",
"checksum": "$(sha256sum backups/mydata_*.tar.gz | awk '{print $1}')"
}
EOF
aws s3 cp backups/manifest_*.json s3://my-backup-bucket/docker-volumes/
Verificación
- Listar objetos en el bucket y confirmar que tanto el tarball como el manifiesto están presentes.
- Validar checksum descargando el archivo y comparando con el valor registrado en el JSON.
- Restaurar en un contenedor de prueba:
Verifica que los archivos esperados aparecen y que la aplicación dentro del contenedor arranca sin errores.
docker run --rm -v restored:/data alpine \ sh -c "tar xzf /backup/mydata_<timestamp>.tar.gz -C /data"
Notas adicionales
- Si tu driver de storage es overlay2, considera usar
docker pauseen el contenedor objetivo antes de crear el snapshot ydocker unpausedespués; la pausa es breve y evita escrituras concurrentes. - Para entornos con Podman la sintaxis es idéntica, solo cambia
dockerporpodman. - Cuando uses cifrado (Restic, Borg), guarda la clave de cifrado fuera del bucket, por ejemplo en un secret manager, para evitar que un backup comprometido sea legible.
- Programa pruebas de restauración mensuales; la única forma de confiar en el proceso es verificar que la recuperación funciona bajo presión.
- Si trabajas con UnraidOS, aprovecha los “share” de Docker que ya exponen los volúmenes como rutas de red; el mismo script funciona sin modificaciones.