Volúmenes y Bind Mounts en Docker


Tutorial de Volúmenes en Docker

📚 Introducción a los Volúmenes de Docker

Los volúmenes en Docker son el mecanismo preferido para persistir datos generados y utilizados por contenedores Docker. A diferencia del sistema de archivos por capas de los contenedores, los volúmenes existen completamente fuera del ciclo de vida del contenedor.

¿Por qué usar volúmenes?

  • Persistencia de datos: Los datos sobreviven al reinicio o eliminación del contenedor

  • Compartir datos: Múltiples contenedores pueden acceder al mismo volumen

  • Backup y migración: Fácil de hacer backup y restaurar

  • Mejor rendimiento: Comparado con bind mounts en algunos sistemas


🛠️ Tipos de Volúmenes

1. Volúmenes Nombrados (Named Volumes)

2. Volúmenes Anónimos (Anonymous Volumes)

3. Bind Mounts


🚀 Ejemplos Prácticos

Ejemplo 1: Crear y usar un volumen nombrado

bash
# Crear un volumen nombrado
docker volume create mi-volumen

# Verificar que el volumen fue creado
docker volume ls

# Inspeccionar el volumen
docker volume inspect mi-volumen

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

# Verificar que el volumen está siendo usado
docker inspect mi-contenedor

Ejemplo 2: Usar volúmenes con MySQL

bash
# Crear un volumen para MySQL
docker volume create mysql-data

# Ejecutar MySQL con el volumen
docker run -d \
  --name mysql-container \
  -e MYSQL_ROOT_PASSWORD=mi_password \
  -v mysql-data:/var/lib/mysql \
  mysql:8.0

# Verificar los datos persisten
docker exec -it mysql-container mysql -pmi_password -e "CREATE DATABASE test_db;"
docker stop mysql-container
docker start mysql-container
docker exec -it mysql-container mysql -pmi_password -e "SHOW DATABASES;"

Ejemplo 3: Bind Mount para desarrollo

bash
# Montar un directorio local en el contenedor
docker run -d \
  --name nginx-dev \
  -p 8080:80 \
  -v $(pwd)/html:/usr/share/nginx/html \
  nginx

# Crear un archivo en el directorio local
echo "<h1>Hola desde bind mount!</h1>" > html/index.html

# Verificar en el navegador: http://localhost:8080

Ejemplo 4: Volumen de solo lectura

bash
# Montar un volumen como solo lectura
docker run -d \
  --name nginx-ro \
  -v mi-volumen:/app/data:ro \
  nginx

📝 Usando Docker Compose con Volúmenes

docker-compose.yml ejemplo:

yaml
version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - web-data:/usr/share/nginx/html
      - ./config/nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - db

  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: app_db
      MYSQL_USER: app_user
      MYSQL_PASSWORD: userpass
    volumes:
      - db-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

volumes:
  web-data:
    driver: local
  db-data:
    driver: local

Ejecutar:

bash
docker-compose up -d

🔧 Comandos Esenciales para Volúmenes

Gestión de Volúmenes

bash
# Listar volúmenes
docker volume ls

# Crear volumen
docker volume create nombre-volumen

# Inspeccionar volumen
docker volume inspect nombre-volumen

# Eliminar volumen
docker volume rm nombre-volumen

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

Backup y Restauración

bash
# Backup de un volumen
docker run --rm -v nombre-volumen:/data -v $(pwd):/backup alpine \
  tar czf /backup/backup.tar.gz -C /data .

# Restaurar un volumen
docker run --rm -v nombre-volumen:/data -v $(pwd):/backup alpine \
  sh -c "rm -rf /data/* && tar xzf /backup/backup.tar.gz -C /data"

🎯 Mejores Prácticas

1. Usar volúmenes nombrados en producción

bash
# ✅ Recomendado
-v mi-volumen-prod:/app/data

# ❌ Evitar en producción
-v /app/data

2. Especificar drivers de volumen cuando sea necesario

bash
docker volume create --driver local \
  --opt type=none \
  --opt device=/path/to/data \
  --opt o=bind \
  nombre-volumen

3. Usar volúmenes para datos críticos

bash
# Para bases de datos
-v db-data:/var/lib/mysql

# Para uploads de usuarios
-v uploads-data:/app/uploads

4. Limpiar volúmenes no utilizados regularmente

bash
docker volume prune

🚨 Solución de Problemas Comunes

Verificar uso de volúmenes

bash
# Ver qué contenedores usan un volumen
docker ps -a --filter volume=nombre-volumen

# Ver espacio usado por volúmenes
docker system df -v

Depurar problemas de permisos

bash
# Inspeccionar el volumen
docker volume inspect nombre-volumen

# Ver contenido del volumen
docker run --rm -v nombre-volumen:/data alpine ls -la /data

Recuperar datos de un volumen

bash
# Copiar datos desde un volumen
docker run --rm -v nombre-volumen:/source -v $(pwd):/backup alpine \
  cp -r /source/* /backup/

📊 Comparación: Volúmenes vs Bind Mounts

CaracterísticaVolúmenesBind Mounts
Persistencia✅ Excelente✅ Depende del host
Portabilidad✅ Alta❌ Baja
Backup✅ Fácil✅ Manual
Rendimiento✅ Bueno✅ Variable
Desarrollo✅ Bueno✅ Excelente

🎓 Ejercicios Prácticos

Ejercicio 1: Aplicación con persistencia

  1. Crea un contenedor WordPress con volúmenes para la base de datos y archivos

  2. Verifica que los datos persisten después de reiniciar

Ejercicio 2: Migración de datos

  1. Crea un volumen con datos

  2. Haz backup del volumen

  3. Restaura en un nuevo volumen

Ejercicio 3: Desarrollo con hot-reload

  1. Configura un contenedor de desarrollo con bind mount

  2. Modifica archivos locales y ve los cambios en tiempo real


📋 Resumen

  • Volúmenes nombrados: Ideales para producción y datos críticos

  • Bind mounts: Perfectos para desarrollo y configuraciones

  • Docker Compose: Simplifica la gestión de volúmenes múltiples

  • Backup regular: Esencial para datos importantes

📁 Introducción a los Volúmenes en Docker

Los volúmenes en Docker permiten conectar carpetas y archivos del host con el contenedor, manteniendo la sincronización entre ambos. Esto es esencial para:

  • Desarrollo: Modificar código en tiempo real

  • Persistencia: Conservar datos cuando el contenedor se elimina

  • Compartir datos: Múltiples contenedores accediendo a los mismos archivos


🚀 Montar una Carpeta Local en el Contenedor

Ejemplo Básico: Proyecto Web

bash
# Sintaxis básica
docker run -v ~/mi-proyecto:/var/www/html mi-imagen

Explicación:

  • ~/mi-proyecto: Ruta absoluta en tu equipo host

  • /var/www/html: Ruta dentro del contenedor

  • mi-imagen: Imagen Docker a utilizar

Ejemplo Práctico con Nginx

bash
# Crear directorio del proyecto
mkdir -p ~/mi-proyecto

# Crear un archivo HTML simple
echo "<h1>Mi Proyecto Web</h1>" > ~/mi-proyecto/index.html

# Ejecutar contenedor Nginx montando la carpeta
docker run -d \
  --name mi-web \
  -p 8080:80 \
  -v ~/mi-proyecto:/usr/share/nginx/html \
  nginx:alpine

# Verificar en el navegador: http://localhost:8080

Modificar en Tiempo Real

bash
# Modificar el archivo desde el host
echo "<h1>Proyecto Modificado</h1>" > ~/mi-proyecto/index.html

# Los cambios se reflejarán inmediatamente en el navegador

🗄️ Persistir Datos de Base de Datos

Ejemplo con MySQL

bash
# Crear directorio para datos de MySQL
mkdir -p ~/mysql-datos

# Ejecutar contenedor MySQL con persistencia
docker run -d \
  --name mysql-db \
  -e MYSQL_ROOT_PASSWORD=mi_password \
  -e MYSQL_DATABASE=mi_app \
  -v ~/mysql-datos:/var/lib/mysql \
  mysql:5.7

# Verificar que los datos persisten
docker exec -it mysql-db mysql -pmi_password -e "SHOW DATABASES;"

# Detener y eliminar el contenedor
docker stop mysql-db
docker rm mysql-db

# Los datos permanecen en ~/mysql-datos
ls -la ~/mysql-datos/

Verificar Persistencia

bash
# Volver a crear el contenedor con los mismos datos
docker run -d \
  --name mysql-db2 \
  -e MYSQL_ROOT_PASSWORD=mi_password \
  -v ~/mysql-datos:/var/lib/mysql \
  mysql:5.7

# Verificar que la base de datos sigue existiendo
docker exec -it mysql-db2 mysql -pmi_password -e "SHOW DATABASES;"

🔄 Comparación: Volúmenes Docker vs Bind Mounts

Docker Volumes (Volúmenes Gestionados)

bash
# Crear volumen gestionado
docker volume create mi-volumen

# Usar volumen en contenedor
docker run -d \
  --name web-app \
  -v mi-volumen:/app/data \
  nginx:alpine

# Los datos se almacenan en /var/lib/docker/volumes/ (solo accesible por Docker)

Bind Mounts (Montajes Directos)

bash
# Usar bind mount (acceso directo)
docker run -d \
  --name web-app \
  -v /home/usuario/mi-proyecto:/app/data \
  nginx:alpine

# Los datos están directamente accesibles en tu sistema de archivos

Tabla Comparativa

CaracterísticaDocker VolumesBind Mounts
GestiónGestionado por DockerGestión manual
PortabilidadAlta (backup fácil)Baja (rutas específicas)
RendimientoVariableGeneralmente mejor
Caso de usoProducción, datos críticosDesarrollo, configuraciones
Ubicación/var/lib/docker/volumes/Cualquier ruta del host

🛠️ Comandos Esenciales para Gestión de Volúmenes

Gestión de Volúmenes Docker

bash
# Listar volúmenes
docker volume ls

# Crear volumen
docker volume create mi-volumen

# Inspeccionar volumen
docker volume inspect mi-volumen

# Eliminar volumen
docker volume rm mi-volumen

# Limpiar volúmenes no utilizados
docker volume prune

Ejemplos con Volúmenes Nombrados

bash
# Crear y usar volumen nombrado
docker volume create app-data

docker run -d \
  --name mi-app \
  -v app-data:/app/storage \
  mi-imagen

# Compartir volumen entre contenedores
docker run -d \
  --name app-1 \
  -v app-data:/shared-data \
  mi-imagen

docker run -d \
  --name app-2 \
  -v app-data:/shared-data \
  mi-imagen

🐍 Ejemplo Práctico: Servidor Flask con Volumen

Estructura del Proyecto

text
~/volumenes/
├── app.py
└── Dockerfile

app.py

python
from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return "Hola Mundo desde Flask en Docker!"

if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0", port=3030)

Dockerfile

dockerfile
FROM python:3.8
EXPOSE 3030
WORKDIR /app
RUN pip install flask
COPY ./app.py ./app.py
ENTRYPOINT ["python3"]
CMD ["app.py"]

Construir y Ejecutar

bash
# Navegar al directorio
cd ~/volumenes

# Construir la imagen
docker build -t volumen ./

# Ejecutar con bind mount para desarrollo
docker run -d \
  -v $(pwd)/app.py:/app/app.py \
  -p 5000:3030 \
  --name flask-app \
  volumen

Desarrollo en Tiempo Real

bash
# Modificar el archivo app.py desde el host
echo '
from flask import Flask
app = Flask(__name__)

@app.route("/")
def index():
    return "¡Mensaje Modificado en Caliente!"

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=3030)
' > app.py

# Los cambios se reflejan automáticamente en http://localhost:5000

📋 Docker Compose para Gestión Simplificada

docker-compose.yml

yaml
version: '3.8'

services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    volumes:
      - ./html:/usr/share/nginx/html
      - ./nginx.conf:/etc/nginx/nginx.conf:ro

  database:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: app_db
    volumes:
      - db-data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

  flask-app:
    build: .
    ports:
      - "5000:3030"
    volumes:
      - ./app.py:/app/app.py
    depends_on:
      - database

volumes:
  db-data:

Comandos Docker Compose

bash
# Iniciar todos los servicios
docker-compose up -d

# Ver logs
docker-compose logs

# Detener servicios
docker-compose down

# Detener y eliminar volúmenes
docker-compose down -v

🔧 Casos de Uso Avanzados

Volumen de Solo Lectura

bash
# Montar volumen como solo lectura
docker run -d \
  -v ~/config:/app/config:ro \
  mi-imagen

Volumen con Permisos Específicos

bash
# Especificar usuario y permisos
docker run -d \
  -v ~/data:/app/data \
  --user 1000:1000 \
  mi-imagen

Múltiples Volúmenes

bash
# Montar múltiples directorios
docker run -d \
  -v ~/html:/var/www/html \
  -v ~/config:/etc/nginx \
  -v ~/logs:/var/log/nginx \
  nginx:alpine

🚨 Solución de Problemas Comunes

Verificar Volúmenes Montados

bash
# Inspeccionar contenedor
docker inspect nombre-contenedor

# Ver volúmenes específicos
docker volume inspect nombre-volumen

# Listar volúmenes utilizados por contenedor
docker ps -a --format "table {{.Names}}\t{{.Mounts}}"

Problemas de Permisos

bash
# Ver permisos del directorio host
ls -la ~/mi-proyecto

# Si hay problemas de permisos, ajustar propietario
sudo chown -R $USER:$USER ~/mi-proyecto

# O ejecutar contenedor con usuario específico
docker run -d --user 1000:1000 -v ~/proyecto:/app mi-imagen

Backup y Restauración

bash
# Backup de volumen
docker run --rm -v mi-volumen:/data -v $(pwd):/backup alpine \
  tar czf /backup/backup.tar.gz -C /data .

# Restaurar volumen
docker run --rm -v mi-volumen:/data -v $(pwd):/backup alpine \
  sh -c "rm -rf /data/* && tar xzf /backup/backup.tar.gz -C /data"

📝 Resumen de Sintaxis

Sintaxis Básica

bash
# Bind mount
docker run -v /ruta/host:/ruta/contenedor imagen

# Volumen Docker
docker run -v nombre-volumen:/ruta/contenedor imagen

# Modificadores
docker run -v /ruta/host:/ruta/contenedor:ro    # Solo lectura
docker run -v /ruta/host:/ruta/contenedor:rw    # Lectura/escritura (default)

Mejores Prácticas

  1. Desarrollo: Usa Bind Mounts para sincronización en tiempo real

  2. Producción: Usa Docker Volumes para mejor portabilidad

  3. Datos críticos: Siempre usa volúmenes para bases de datos

  4. Backup: Programa backups regulares de volúmenes importantes

  5. Permisos: Verifica permisos entre host y contenedor


🎯 Conclusión

Los volúmenes y bind mounts son esenciales para:

  • ✅ Persistencia de datos entre ciclos de vida del contenedor

  • ✅ Desarrollo ágil con cambios en tiempo real

  • ✅ Backup y recuperación de datos importantes

  • ✅ Compartir datos entre múltiples contenedores

Comentarios

Entradas más populares de este blog

ejercicios-Crear Carpeta y Archivo de Texto en Ubuntu

Instalar Docker en Ubuntu Server usando docker.io

Tutorial de Carpetas y Directorios en Ubuntu Linux