Por qué un contenedor pierde sus datos al reiniciarse

Escribe una fila en una base de datos que corre en un contenedor de Docker, para el contenedor y arráncalo otra vez: la fila ya no está.

Cada contenedor recibe su sistema de archivos recién sacado de su imagen cada vez que arranca. Todo lo que el propio contenedor escribe (archivos de base de datos, subidas, logs) va a parar a una capa de escritura que se descarta cuando el contenedor se elimina. Un volumen Docker es la forma de mantener esos datos fuera del contenedor, donde sobreviven.

¿Qué es un Volumen Docker?

Un volumen Docker es un mecanismo para guardar los datos fuera del contenedor, de manera que persistan incluso cuando el contenedor se para, reinicia o elimina.

Piensa en los volúmenes como un disco duro externo que conectas a tu contenedor. Los datos se escriben en este “disco externo” y permanecen seguros independientemente de lo que le pase al contenedor.

¿Por Qué Usar Volúmenes?

  • Persistencia: los datos sobreviven al ciclo de vida del contenedor
  • Compartición: varios contenedores pueden acceder a los mismos datos
  • Backup: es más fácil hacer copias de seguridad de los datos
  • Rendimiento: los volúmenes están optimizados para las operaciones I/O
  • Portabilidad: puedes mover los datos entre diferentes hosts

Volúmenes, bind mounts y tmpfs: cuál usar

Hay tres formas de persistir datos, en el orden en que deberías recurrir a ellas: volúmenes, bind mounts, tmpfs.

1. Volúmenes (Volumes) - La Elección Recomendada

Los volúmenes son gestionados completamente por Docker y guardados en un directorio especial en el host (/var/lib/docker/volumes/ en Linux).

1
2
3
4
5
# Crear un volumen
docker volume create mi-volumen

# Usar el volumen en un contenedor
docker run -v mi-volumen:/app/data mi-imagen

Ventajas:

  • Gestionados por Docker (fáciles de crear, eliminar, inspeccionar)
  • Funcionan en Linux, Windows y Mac
  • Pueden compartirse entre varios contenedores
  • Soportan drivers para almacenamiento remoto (cloud, NFS, etc.)

2. Bind Mounts - Conexión Directa

Los bind mounts conectan una carpeta específica de tu ordenador directamente al contenedor.

1
2
# Conectar una carpeta local al contenedor
docker run -v /ruta/en/tu/pc:/app/data mi-imagen

Cuándo usarlos:

  • Durante el desarrollo, para ver los cambios en el código en tiempo real
  • Cuando necesitas acceder a archivos específicos del sistema host
  • Para compartir configuraciones entre host y contenedor

Atención: los bind mounts dependen de la estructura del sistema de archivos del host, por lo que son menos portables.

3. tmpfs Mounts - Datos Temporales en Memoria

Los tmpfs mounts guardan los datos en la RAM del host, no en disco.

1
docker run --tmpfs /app/temp mi-imagen

Cuándo usarlos:

  • Para datos sensibles que no deben escribirse en disco
  • Para cachés temporales de alto rendimiento
  • Los datos se pierden cuando el contenedor se para (y eso es exactamente lo que quieres)

Comandos de volúmenes Docker: create, list, inspect, remove

Crear un Volumen

1
docker volume create nombre-volumen

Listar los Volúmenes

1
docker volume ls

Inspeccionar un Volumen

1
docker volume inspect nombre-volumen

Este comando muestra dónde está físicamente guardado el volumen y otra información útil.

Eliminar un Volumen

1
2
3
4
5
# Eliminar un volumen específico
docker volume rm nombre-volumen

# Eliminar todos los volúmenes no utilizados
docker volume prune

Atención: eliminar un volumen significa perder todos los datos contenidos. No hay papelera ni recuperación.

Ejemplos de volúmenes Docker: base de datos, desarrollo con recarga, compartir

Ejemplo 1: Base de Datos MySQL con Datos Persistentes

Sin volumen, cada vez que reinicias el contenedor MySQL pierdes todos los datos. Así es cómo resolverlo:

1
2
3
4
5
6
7
8
9
# Crear un volumen para los datos de MySQL
docker volume create mysql-data

# Iniciar MySQL usando el volumen
docker run -d \
  --name mi-mysql \
  -e MYSQL_ROOT_PASSWORD=password123 \
  -v mysql-data:/var/lib/mysql \
  mysql:8

Ahora puedes parar, reiniciar o incluso eliminar y recrear el contenedor: los datos de la base de datos permanecerán intactos en el volumen mysql-data.

Ejemplo 2: Desarrollo Web con Bind Mount

Durante el desarrollo, quieres que las modificaciones al código sean inmediatamente visibles en el contenedor:

1
2
3
4
5
docker run -d \
  --name mi-sitio \
  -p 8080:80 \
  -v $(pwd)/src:/var/www/html \
  php:apache

Cada modificación a los archivos en la carpeta src estará inmediatamente disponible en el contenedor.

Ejemplo 3: Compartir Datos entre Contenedores

Dos contenedores que deben acceder a los mismos archivos:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Crear el volumen compartido
docker volume create datos-compartidos

# Contenedor que escribe
docker run -d --name escritor -v datos-compartidos:/data alpine \
  sh -c "while true; do date >> /data/log.txt; sleep 5; done"

# Contenedor que lee
docker run -it --name lector -v datos-compartidos:/data alpine \
  tail -f /data/log.txt

Volúmenes en Docker Compose

En Docker Compose declaras los volúmenes una vez y cada servicio que los necesita los referencia por su nombre:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
version: '3.8'

services:
  database:
    image: postgres:15
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: secret

  app:
    image: mi-app
    volumes:
      - ./codigo:/app          # Bind mount para desarrollo
      - logs:/app/logs         # Volumen para los logs

volumes:
  postgres-data:    # Volumen gestionado por Docker
  logs:             # Volumen gestionado por Docker

Con un simple docker-compose up, Docker crea automáticamente los volúmenes necesarios.

Backup y Restauración de Volúmenes

Hacer Backup de un Volumen

1
2
3
4
docker run --rm \
  -v nombre-volumen:/source:ro \
  -v $(pwd):/backup \
  alpine tar czf /backup/backup.tar.gz -C /source .

Este comando:

  1. Monta el volumen en solo lectura (ro)
  2. Crea un archivo comprimido en el directorio actual

Restaurar un Backup

1
2
3
4
docker run --rm \
  -v nombre-volumen:/target \
  -v $(pwd):/backup \
  alpine tar xzf /backup/backup.tar.gz -C /target

Errores habituales con los volúmenes Docker

1. Olvidar Usar Volúmenes para las Bases de Datos

Si usas una base de datos en Docker sin volumen, perderás todos los datos. Siempre.

2. Usar Bind Mounts en Producción

Los bind mounts son geniales para el desarrollo, pero en producción usa volúmenes Docker para mayor portabilidad y seguridad.

3. No Hacer Backup de los Volúmenes

Los volúmenes no se incluyen automáticamente en los backups del sistema. Planifica backups regulares.

4. Acumular Volúmenes Huérfanos

Cuando eliminas contenedores, los volúmenes permanecen. Usa periódicamente:

1
docker volume prune

Para eliminar los volúmenes que ya no están conectados a ningún contenedor.

Qué opción de almacenamiento para cada caso

EscenarioSolución
Base de datos en producciónVolumen Docker
Desarrollo localBind mount
Datos sensibles temporalestmpfs
Compartición entre contenedoresVolumen Docker
Archivos de configuraciónBind mount o Volumen
Logs de aplicaciónVolumen Docker

La regla que cubre casi todos los casos

Usa un volumen con nombre para todo lo que un contenedor escriba y quieras conservar, empezando por las bases de datos. Usa un bind mount cuando quieras que el contenedor vea una carpeta de tu máquina según la editas, que es sobre todo el desarrollo local. Deja tmpfs para los datos que nunca deben tocar el disco.

Cuando una base de datos tiene un volumen, puedes borrar y recrear su contenedor tantas veces como quieras y los datos siguen ahí. Ese es todo el objetivo.

Artículos relacionados