Skip to content

Tema:

Utilizando Almacenamiento Persistente en Contenedores Docker


Introducción

El almacenamiento persistente en contenedores Docker es un tema crucial para garantizar la durabilidad de los datos generados y consumidos por las aplicaciones que se ejecutan en contenedores. Aunque los contenedores son efímeros por naturaleza, muchas aplicaciones requieren mantener datos más allá del ciclo de vida de un contenedor, como bases de datos, configuraciones, archivos de usuario, y más.

En este tema exploraremos cómo Docker maneja el almacenamiento, las opciones disponibles para configurar volúmenes persistentes y montajes, así como las mejores prácticas para garantizar la integridad, escalabilidad y seguridad de los datos. Esto permitirá a los participantes comprender y aplicar estrategias de almacenamiento para soportar aplicaciones más complejas y críticas en entornos de producción.


Objetivo

Objetivo General:

  • Proveer a los participantes los conocimientos y habilidades necesarios para configurar y gestionar almacenamiento persistente en contenedores Docker, garantizando la durabilidad y disponibilidad de los datos en aplicaciones contenerizadas. Los participantes aprenderán a identificar las diferentes opciones de almacenamiento, implementar volúmenes y montajes en diversos escenarios, y aplicar las mejores prácticas para integrar almacenamiento persistente de manera efectiva en entornos de contenedores.

Opciones de Almacenamiento persistente

Existen dos formas de proporcionar almacenamiento persistente a los contenedores:

  • Volumes
  • Bind mounts

Los volúmenes son el mecanismo preferido para conservar los datos generados y utilizados por los contenedores de Docker. Si bien los Bind mounts dependen de la estructura de directorios y del sistema operativo de la máquina host, los volúmenes son completamente administrados por Docker. Los volúmenes tienen varias ventajas sobre los montajes de enlace:

  • Es más fácil realizar copias de seguridad o migrar volúmenes que montajes enlazados.
  • Puede administrar volúmenes mediante los comandos CLI de Docker o la API de Docker.
  • Los volúmenes funcionan en contenedores de Linux y Windows.
  • Los volúmenes se pueden compartir de forma más segura entre varios contenedores.
  • Además, los volúmenes suelen ser una mejor opción que persistir los datos en la capa escribible de un contenedor, porque un volumen no aumenta el tamaño de los contenedores que lo utilizan y el contenido del volumen existe fuera del ciclo de vida de un contenedor determinado.

🚀 Diferencia entre docker run -v y docker run --mount

Las opciones -v y --mount en docker run se utilizan para adjuntar volúmenes o directorios a un contenedor, pero tienen diferencias clave en cuanto a sintaxis, flexibilidad y usabilidad.

🔹 Diferencias entre -v y --mount

Opción -v (o --volume) --mount
Sintaxis -v <host_path>:<container_path>[:opciones] --mount type=<tipo>,source=<host_path>,target=<container_path>,<opciones>
Facilidad de uso Más corta, útil para configuraciones rápidas. Más descriptiva y flexible.
Soporte de opciones Soporta ro (solo lectura), rw (lectura/escritura) y z/Z para SELinux. Soporta readonly, bind-propagation, tmpfs-size, etc.
Compatibilidad con Docker Compose Se usa en docker-compose.yml pero con sintaxis diferente. Se prefiere en docker-compose para mayor claridad.
Mejor práctica Útil para compatibilidad con versiones anteriores de Docker. Se recomienda para nuevas implementaciones.

🔹 Ejemplos de Uso

1️⃣ Usando -v (opción más antigua y compacta)

docker run -v /host/data:/container/data:ro ubuntu
Explicación:

  • Monta el directorio /host/data del host en /container/data dentro del contenedor.
  • ro (opcional) indica que el volumen es solo lectura.

2️⃣ Usando --mount (más descriptivo y flexible)

docker run --mount type=bind,source=/host/data,target=/container/data,readonly \
ubuntu
Explicación:

  • type=bind indica que se monta un directorio del host.
  • source=/host/data especifica el directorio en el host.
  • target=/container/data indica dónde se montará en el contenedor.
  • readonly hace que el volumen sea de solo lectura.

3️⃣ Montando un volumen con -v

docker run -v my_volume:/container/data ubuntu
Explicación:

  • my_volume es un volumen administrado por Docker.
  • Se montará en /container/data en el contenedor.

4️⃣ Montando un volumen con --mount

docker run --mount type=volume,source=my_volume,target=/container/data ubuntu
Explicación:

  • type=volume indica que se usa un volumen administrado por Docker.
  • source=my_volume es el nombre del volumen.
  • target=/container/data es el destino dentro del contenedor.

📌 Cuál usar y cuándo

✅ Usa -v para configuraciones rápidas o compatibilidad con versiones antiguas.
✅ Usa --mount para configuraciones más claras y flexibles, especialmente en docker-compose y entornos de producción

Creación y Administración de Volumenes

Crear un volumen:

docker volume create example-vol
Lista de volúmenes:
docker volume ls
La salida del comando anterior debe ser similar a la siguiente:
local               example-vol
Inspeccionar un volumen:
docker volume inspect example-vol
La salida del comando anterior debe ser similar a la siguiente:
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/example-vol/_data",
        "Name": "example-vol",
        "Options": {},
        "Scope": "local"
    }
]
Eliminar un volumen:
docker volume rm example-vol

Iniciar un contenedor con un volumen

Si inicia un contenedor con un volumen que aún no existe, Docker crea el volumen por usted. El siguiente ejemplo monta el volumen demovol en /app/ del contenedor.

docker run -d \
--name demovol-container \
--mount source=demovol,target=/app \
nginx:latest
Puedes utilizar docker inspect demovol-container para verificar que Docker creó el volumen y se montó correctamente. Busque la Mountssección:
docker inspect demovol-container
La salida del comando anterior debe ser similar a la siguiente:
"Mounts": [
    {
        "Type": "volume",
        "Name": "demovol",
        "Source": "/var/lib/docker/volumes/demovol/_data",
        "Destination": "/app",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
],
docker exec demovol-container df -h
Esto demuestra que el montaje es un volumen, muestra el origen y el destino correctos y que el montaje es de lectura y escritura. Detener el contenedor y eliminar el volumen.
docker stop demovol-container
docker rm demovol-container
docker volume rm demovol

Guía de Laboratorio: Usar Docker Volumes con un contenedor NGINX para un Sitio Web

En esta guía, configuraremos un contenedor NGINX para servir un sitio web sencillo utilizando un Docker Volume. Veremos cómo persistir los datos del sitio, de manera que estos permanezcan disponibles incluso si el contenedor se elimina y se recrea.

Paso 1: Crear un Docker Volume

Primero, crearemos un volumen en Docker para almacenar los datos del sitio web de forma persistente.

docker volume create webdata

Este comando crea un volumen llamado webdata, que usaremos para almacenar los archivos de nuestro sitio web.

Paso 2: Crear el contenido del sitio web

Crea un archivo index.html localmente para usarlo como contenido del sitio web.

  1. Crea una carpeta temporal:
    mkdir ~/nginx-site
    
  2. Crea un archivo index.html dentro de esta carpeta:
    echo "<h1>Bienvenido a mi sitio web</h1>" > ~/nginx-site/index.html
    

Paso 3: Iniciar el contenedor NGINX con el volumen

Montaremos el volumen webdata en el contenedor para que sirva los archivos del sitio web.

docker run -d \
  --name nginx-container \
  -p 8080:80 \
  -v webdata:/usr/share/nginx/html \
  nginx

Este comando:

  • Inicia un contenedor NGINX en segundo plano (-d).
  • Lo expone en el puerto 8080 de tu máquina host.
  • Monta el volumen webdata en el directorio /usr/share/nginx/html, que es donde NGINX busca los archivos a servir.

Paso 4: Copiar el contenido del sitio al volumen

Los volúmenes se encuentran vacíos al principio, por lo que necesitamos copiar el archivo index.html creado en el Paso 2 al volumen.

  1. Usa un contenedor temporal para copiar el archivo al volumen:

    docker run --rm \
      -v ~/nginx-site:/site \
      -v webdata:/usr/share/nginx/html \
      busybox cp /site/index.html /usr/share/nginx/html/
    

  2. Verifica que el archivo se haya copiado al volumen:

    docker run --rm \
      -v webdata:/data \
      busybox ls /data
    

Deberías ver el archivo index.html listado.

Paso 5: Probar el sitio web

Utilizar el siguiente comando:

curl http://localhost:8080

Deberías ver el mensaje:
"Bienvenido a mi sitio web"

Paso 6: Eliminar el contenedor y recrearlo

  1. Elimina el contenedor NGINX actual:

    docker rm -f nginx-container
    

  2. Vuelve a crear el contenedor usando el volumen persistente:

    docker run -d \
      --name nginx-container \
      -p 8080:80 \
      -v webdata:/usr/share/nginx/html \
      nginx
    

  3. Verifica nuevamente el sitio web:

    curl http://localhost:8080
    

El sitio web debería seguir mostrándose, confirmando que los datos se han mantenido en el volumen.

Paso 7: Limpieza

Si ya no necesitas este entorno, puedes eliminar el contenedor y el volumen.

  1. Eliminar el contenedor:

    docker rm -f nginx-container
    

  2. Eliminar el volumen:

    docker volume rm webdata
    

  3. Eliminar la carpeta temporal:

    rm -Rf ~/nginx-site
    

Conclusión

Has configurado un contenedor NGINX con un volumen persistente, probado la persistencia de datos al eliminar y recrear el contenedor, y aprendido cómo gestionar volúmenes en Docker.

Guía de Laboratorio: Utilizando almacenamiento persistente en Data Base Container

La presente guía descubre y aplica el uso de volúmenes compartidos para persistir data de importancia en contenedores.

  1. Ingresar al servidor qué contiene al ambiente de laboratorio con credenciales de administración

  2. Crear un directorio

    sudo mkdir -pv /var/local/mysql
    

  3. Cambiar uid y gid de forma recursiva al directorio

    sudo chown -Rv 999:999 /var/local/mysql
    

  4. Descargar imagen mariadb:10.7

    docker pull mariadb:10.7
    

  5. Iniciar el contenedor con la imagen de mariadb:10.7 con los siguientes parámetros (listados con - nombre completo pero, en comando abreviados):

    • name=persist-db
    • remove=true
    • volume=/var/local/mysql:/var/lib/mysql
    • environment=MYSQL_USER=user1
    • environment=MYSQL_PASSWORD=demo
    • environment=MYSQL_DATABASE=inventory
    • environment=MYSQL_ROOT_PASSWORD=demo
      docker run --name persist-db \
      -v /var/local/mysql:/var/lib/mysql \
      -e MYSQL_USER=user1 \
      -e MYSQL_PASSWORD=demo \
      -e MYSQL_DATABASE=inventory \
      -e MYSQL_ROOT_PASSWORD=demo -d mariadb:10.7
      
  6. Listar los contenedores activos

    docker ps
    

  7. Aplicar formato a la lista de contenedores

    docker ps --format="\nNAME: {{.Names}} | STATUS: {{.Status}} | IMAGE: {{.Image}}\n"
    

  8. Listar contenido de directorio local

    ls -l /var/local/mysql
    

Cambios en data

  1. Ingrese al contenedor persist-db y agregue una tabla y un registro en la base de datos creada de mariadb

    docker exec -it persist-db bash
    
    mysql -u user1 -pdemo -D inventory
    
    CREATE TABLE customers(id INT, first_name VARCHAR(50), last_name VARCHAR (50), email VARCHAR(100));
    INSERT INTO customers VALUES(1, 'Anne', 'Ketchmar', 'annek@noanswer.org');
    exit
    
    exit
    

  2. Detenga el contenedor

    docker stop persist-db
    

  3. Vea el contenido de la carpeta /var/local/mysql

    ls -l /var/local/mysql
    

  4. Vuelva a iniciar el contenedor

    docker start persist-db
    

  5. Revise que el record de la tabla customers exista

    docker exec -it persist-db bash
    
    mysql -u user1 -pdemo -D inventory
    
    SELECT * FROM customers;
    exit
    
    exit
    

  6. Detenga y elimine el contenedor

    docker stop persist-db
    
    docker rm persist-db
    

  7. Verifique que la carpeta /var/local/mysql aun exista en la máquina

    ls -l /var/local/mysql
    

  8. Cree otro contenedor de mariadb

    docker run --name persist-db \
    -v /var/local/mysql:/var/lib/mysql \
    -e MYSQL_USER=user1 \
    -e MYSQL_PASSWORD=demo \
    -e MYSQL_DATABASE=inventory \
    -e MYSQL_ROOT_PASSWORD=demo -d mariadb:10.7
    

  9. Verifique que la tabla customers exista

    docker exec -it persist-db bash
    
    mysql -u user1 -pdemo -D inventory
    
    SELECT * FROM customers;
    exit
    
    exit
    

  10. Cree una carpeta en /var/local/mysql llamada custom-dir

    sudo mkdir /var/local/mysql/custom-dir
    

  11. Ejecute dentro del contenedor el comando para listar los archivos dentro del directorio /var/lib/mysql

    docker exec -it persist-db ls -l /var/lib/mysql
    

  12. Observe que el directorio custom-dir existe dentro del contenedor

  13. Acceda al contenedor abriendo una terminal bash con docker

    docker exec -it persist-db bash
    

  14. Cree un archivo vacío dentro de la carpeta custom-dir

    touch /var/lib/mysql/custom-dir/example.txt
    

  15. Salga de la terminal del contenedor

    exit
    

  16. Verifique los archivos del directorio custom-dir en su máquina

    ls -l /var/local/mysql/custom-dir
    

  17. Observe que ahora existe el archivo example.txt

  18. Agregue el siguiente contenido al archivo example.txt

    sudo vi /var/local/mysql/custom-dir/example.txt
    
    # Este archivo no afecta al funcionamiento de MariaDB
    # Su contenido no se lee por ningún servicio
    Uso: Prueba de almacenamiento persistente en Docker
    

  19. Guarde los cambios

  20. Verifique en el contenedor de mariadb el contenido del archivo example.txt

    docker exec -it persist-db cat /var/lib/mysql/custom-dir/example.txt
    

Limpieza de ambiente

  1. Limpiar el ambiente ejecutando
    docker stop persist-db
    
    docker rm persist-db
    
    sudo rm -r /var/local/mysql
    
    docker image rm mariadb:10.7