docker

Cómo hacer backup de volúmenes Docker

Guía práctica para hacer y restaurar backups de volúmenes Docker con un contenedor temporal y tar, respetando consistencia, permisos y bases de datos.

16 de septiembre de 2026·10 min de lectura

Los volúmenes Docker guardan los datos que un contenedor necesita conservar entre reinicios: un archivo de configuración, un directorio de subida de usuarios o la base de datos de una aplicación. Un contenedor se recrea en segundos; los datos que hay dentro de un volumen no se recrean solos. Por eso, si algo merece copia de seguridad, son los volúmenes.

Esta guía (que asume Docker instalado) explica cómo hacer y restaurar backups de volúmenes con las herramientas del propio Docker, sin instalar nada adicional.

Qué es un volumen Docker

Un named volume (volumen con nombre) es un directorio gestionado por Docker bajo /var/lib/docker/volumes/. Se declara con un nombre y se monta en una ruta dentro del contenedor:

docker run -d --name web -v mis-datos:/var/lib/nginx nginx:alpine

El volumen mis-datos aparece en la ruta /var/lib/nginx de ese contenedor. La clave para hacer el backup es esa relación: volumen con nombre ↔ ruta de montaje.

Existe otra forma de montar datos, el bind mount, donde montas un directorio concreto del servidor (por ejemplo -v /home/mateo/datos:/datos). En ese caso tu propia máquina ya guarda los datos en esa carpeta: el “backup” es copiar ese directorio normal, sin intervención de Docker. Aquí nos centramos en los named volumes, que son los que viven escondidos por Docker.

Por qué hacer backups

  • Los contenedores e imágenes se pueden regenerar; el contenido de un volumen no.
  • docker volume rm o un error de manipulación borran los datos de forma definitiva.
  • Al recrear un contenedor con la misma imagen, el volumen persiste — pero un problema de disco o un docker compose down -v no tiene marcha atrás sin una copia.

Listar los volúmenes

docker volume ls
DRIVER    VOLUME NAME
local     mis-datos

Para ver detalles sobre uno concreto (su ubicación real en el host, aunque rara vez la necesitarás):

docker volume inspect mis-datos

Identificar qué volumen usa un contenedor

Necesitas saber el nombre del volumen y la ruta donde está montado, porque la usarás en los comandos de backup. Con un contenedor ejecutándose:

docker inspect --format '{{json .Mounts}}' web
[{"Type":"volume","Name":"mis-datos","Source":"/var/lib/docker/volumes/mis-datos/_data","Destination":"/var/lib/nginx","Driver":"local",...}]

Fíjate en Name (el volumen) y Destination (la ruta dentro del contenedor). Alternativa legible si el JSON te resulta incómodo:

docker inspect web | grep -i -A2 '"Volume"'

Detener el contenedor antes de copiar

Lo más seguro es detener el contenedor y esperar a que suelte los archivos:

docker stop web

Riesgo clave: copiar el contenido de un volumen mientras la aplicación está escribiendo puede producir un backup con archivos a medias o estados inconsistentes. tar no detecta que estás copiando un archivo que otro proceso está modificando. Para datos triviales (copiar una carpeta de assets) la interrupción es asumible; para aplicaciones con estado, detén el contenedor.

Si el volumen guarda una base de datos (PostgreSQL, MySQL, etc.), copiar el directorio de datos es un backup físico que solo es fiable si detienes el servicio o usas un snapshot a bajo nivel. La vía recomendada para backups consistentes de estas bases de datos es usar sus propias herramientas (pg_dump, mysqldump), no copiar el volumen. Lo desarrollamos más abajo.

Crear un backup con un contenedor temporal y tar

La técnica estándar usa un contenedor desechable de Alpine (imagen pequeña) que monta el volumen y un directorio del host a la vez, y empaqueta con tar:

docker run --rm \
  -v mis-datos:/datos \
  -v "$PWD":/backup \
  alpine tar czf /backup/backup-mis-datos-$(date +%Y%m%d).tar.gz -C /datos .

Qué hace cada parte:

  • --rm: elimina el contenedor temporal al terminar.
  • -v mis-datos:/datos: monta el volumen dentro del contenedor.
  • -v "$PWD":/backup: monta el directorio actual del host para guardar el archivo tuyo.
  • tar czf /backup/backup-…tar.gz -C /datos .: comprime el contenido del volumen (todo lo que cuelga de /datos) en un tar gzip. El -C /datos . es importante para que el archivo contenga raíz de /datos, no la carpeta entera.
  • $(date +%Y%m%d): añade la fecha al nombre, clave para no sobrescribir backups antiguos.

Ejecútalo desde la carpeta donde quieras dejar el backup. Al terminar tendrás un archivo tipo backup-mis-datos-20260916.tar.gz en esa carpeta, y el contenedor temporal habrá desaparecido.

Comprobar el contenido del backup

Antes de dar el backup por bueno, lista su interior sin extraerlo:

tar tzf backup-mis-datos-20260916.tar.gz

Debes ver las rutas del contenido del volumen (por ejemplo ./index.html si era Nginx). Vacío aquí = algo falló en el montaje, no en la aplicación.

Restaurar un backup

Restaurar significa volcar el contenido del tar dentro del volumen. Con el contenedor detenido:

docker run --rm \
  -v mis-datos:/datos \
  -v "$PWD":/backup \
  alpine tar xzf /backup/backup-mis-datos-20260916.tar.gz -C /datos

tar xzf … -C /datos extrae el contenido del tar dentro del volumen. Después de restaurar, revisa que los datos están donde deben:

docker run --rm -v mis-datos:/datos alpine ls -l /datos

Y arranca el contenedor:

docker start web

Permisos y propietarios

El contenedor temporal corre como root, así que los archivos extraídos pueden quedar a nombre de root, aunque la aplicación dentro del contenedor original esperase otra UID (por ejemplo, Nginx corre como el usuario nginx). Dos comprobaciones:

  • ls -l sobre /datos te muestra UID/GID (numéricos) de lo restaurado.
  • Si los permisos difieren de lo que espera la app, corrígelos con chmod o chown dentro del mismo contenedor temporal:
docker run --rm -v mis-datos:/datos alpine chown -R nginx:nginx /datos

¿Necesitas el UID exacto de la imagen? Consulta su Dockerfile o prueba a ejecutarla y ver qué usuario usa. No asumas que coincide con tu usuario del host: en named volumes Docker maneja los datos con UID numéricos.

La propia ruta del target (/datos en el tar, -C /datos al restaurar) debe coincidir entre backup y restauración, o el árbol se descoloca. Mantén el mismo nombre de volumen y la misma ruta de montaje para no complicarte — los comandos de esta guía ya lo hacen.

Recomendaciones antes de restaurar

  • Detén la aplicación: no restaures mientras el contenedor usa el volumen, o pisarás archivos en uso.
  • Guarda una copia del estado actual antes de tocar nada: si la restauración sale mal, puedes volver atrás en vez de quedarte sin nada.
  • Comprueba de qué fecha es el backup y que es el que realmente quieres restaurar; restaurar un backup viejo sobre datos más recientes destruye los cambios nuevos.
  • Restaura sobre el mismo volumen (mismo nombre) o con toda la intención de reasignar nombres: cambiar el nombre del volumen desvincula los datos del contenedor original si este no se actualiza.

Riesgos de copiar datos en caliente

La regla es simple: la consistencia la da la aplicación, no tar. Si un proceso está escribiendo cuando compones el backup:

  • El archivo puede quedar truncado o a medias.
  • Puede que ni siquiera estés copiando el directorio completo (bases de datos con archivos de transacciones pendientes).

Por eso el flujo correcto para un servicio con estado es: docker stop → backup → docker start. Si el servicio no puede pararse, la alternativa profesional es un snapshot del volumen (LVM, herramienta de la nube) o las herramientas de dump de la propia base de datos.

Bases de datos: usa dump, no tar del volumen

Para PostgreSQL:

docker exec web-db pg_dump -U postgres mi-base > backup.sql

Para MySQL/MariaDB:

docker exec web-db mysqldump -u root mi-base > backup.sql

Un dump es una copia lógica y consistente que la base de datos genera sin que tengas que copiar su directorio interno. Restaurarla es volcarla de vuelta:

cat backup.sql | docker exec -i web-db psql -U postgres mi-base

Este método es preferible a empaquetar /var/lib/postgresql/data a mano, porque el directorio de datos de un motor puede contener cachés o archivos de transacciones que no deben copiarse en caliente.

Ejemplo completo: backup y restauración de un volumen

Pongamos un contenedor con un volumen sencillo (p. ej. los datos de una app web que escribe en /app/data):

# 1. Crear el contenedor con su volumen
docker run -d --name app -v app-data:/app/data alpine sleep 3600

# 2. Tocar un archivo para tener algo que respaldar
docker exec app sh -c 'echo "hola" > /app/data/leeme.txt'

# 3. Detener la app (datos quietos) y crear el backup
docker stop app
docker run --rm -v app-data:/datos -v "$PWD":/backup alpine tar czf /backup/app-$(date +%Y%m%d).tar.gz -C /datos .

# 4. Verificar contenido
tar tzf app-20260916.tar.gz

Para restaurarlo, supongamos que se ha perdido el volumen:

# Recrear el volumen (si no existe) y volcar el tar dentro
docker volume create app-data
docker run --rm -v app-data:/datos -v "$PWD":/backup alpine tar xzf /backup/app-20260916.tar.gz -C /datos

# Arrancar de nuevo la app con el volumen restaurado
docker start app

# Comprobar
docker exec app cat /app/data/leeme.txt   # → hola

Los valores que debes tener localizados en tu caso real son tres: nombre del volumen, ruta de montaje y dónde dejas el tar.

Errores comunes

El backup sale vacío (tar con un solo directorio o sin archivos)

Suele pasar por escribir tar czf /backup/x.tar.gz /datos sin el -C /datos .. Deja -C /datos . para empaquetar el contenido y no la carpeta entera.

Permission denied al leer el volumen

Si el volumen se montó con otra UID, el proceso alpine (root) normalmente puede leerlo, pero al restaurar conviene revisar que los permisos sean los esperados — ver apartado de permisos.

Restauro y la app no encuentra los datos

Revisa si el nombre del volumen coincide (si creaste uno nuevo con docker volume create, el contenedor debe montar ese mismo nombre) y si la ruta de montaje es la misma. También verifica que el tar contiene lo que esperabas con tar tzf.

Backup de una base de datos que se corrompe

Es el síntoma de copiar un directorio de datos en caliente. Detén el servicio o usa el dump de la propia base — repetir el tar sobre una BD activa no lo arregla.

Conclusión

Un backup de volúmenes con tar y un contenedor temporal es simple, reproducible y no instala nada: pará lo que escriba, monta volumen + host, empaqueta y verifica. Y ante bases de datos, prioriza siempre pg_dump/mysqldump. Con tener localizado el trío volumen–ruta–archivo y la costumbre de comprobar cada backup, tus datos Docker dejan de depender de que “el disco sea afortunado”.

Si gestionas varios servicios con nombres de volúmenes declarados (como el pgdata de un compose.yml), el flujo de esta guía encaja igual: localiza el volumen con docker volume ls y aplica los mismos pasos. Puedes ver cómo declarar y montar volúmenes con Docker Compose para volúmenes multi-servicio.