Cómo compartir datos entre contenedores Docker

Introducción

Docker es una popular herramienta de contenedorización utilizada para proporcionar aplicaciones de software con un sistema de archivos que contiene todo lo que necesitan para ejecutarse. El uso de contenedores Docker garantiza que el software se comportará de la misma manera. Esto independientemente de dónde se implemente, ya que su entorno de tiempo de ejecución es coherente.

En general, los contenedores Docker son efímeros y se ejecutan todo el tiempo necesario para que se complete el comando emitido en el contenedor. A veces, sin embargo, las aplicaciones necesitan compartir el acceso a los datos o persistir después de eliminar un contenedor. Las bases de datos, el contenido generado por el usuario para un sitio web y los archivos de registro. Estos son algunos ejemplos de datos que no son prácticos o imposibles de incluir en una imagen de Docker, pero a qué aplicaciones necesitan acceder. El acceso persistente a los datos se proporciona con volúmenes en Docker.

Los Docker Volumes (volúmenes de docker) pueden crearse y adjuntarse en el mismo comando que crea un contenedor, o pueden crearse independientemente de cualquier contenedor y adjuntarse más tarde. En este artículo, veremos cuatro formas diferentes de compartir datos entre contenedores.

Prerrequisitos

Para seguir este artículo, necesitarás un servidor Ubuntu 18.04 con lo siguiente:

Nota: Los requisitos previos dan instrucciones para instalar Docker en Ubuntu 18.04. Empero, los comandos docker para los volúmenes de datos de Docker en este artículo deberían funcionar en otros sistemas operativos. Esto siempre que Docker esté instalado y el usuario de sudo haya sido agregado al grupo docker.

Paso 1: creación de un volumen independiente

Introducido en la versión 1.9 de Docker, el comando docker volume create te permite crear un volumen sin relacionarlo con ningún contenedor en particular. Usaremos este comando para agregar un volumen llamado DataVolume1:

Se muestra el nombre, lo que indica que el comando se realizó correctamente:

Para hacer uso del volumen, crearemos un nuevo contenedor a partir de la imagen de Ubuntu, utilizando el indicador –rm para eliminarlo automáticamente cuando salgamos. También usaremos –v para montar el nuevo volumen. –v requiere el nombre del volumen, dos puntos, luego la ruta absoluta a donde debe aparecer el volumen dentro del contenedor. Si los directorios en la ruta no existen como parte de la imagen, se crearán cuando se ejecute el comando. Si existen, el volumen montado ocultará el contenido existente:

Mientras estés en el contenedor, escribe algunos datos en el volumen:

Debido a que usamos el indicador –rm, nuestro contenedor se eliminará automáticamente cuando salgamos. Nuestro volumen, sin embargo, seguirá siendo accesible.

Podemos verificar que el volumen esté presente en nuestro sistema con docker volume inspect:

Nota: Incluso podemos ver los datos en el host en la ruta indicada como Mountpoint. Sin embargo, debemos evitar alterarlo, ya que puede causar daños en los datos si las aplicaciones o los contenedores no son conscientes de los cambios.

A continuación, comencemos un nuevo contenedor y adjuntemos DataVolume1:

Para verificar los contenidos:

Debes salir del contenedor:

En este ejemplo, creamos un volumen, lo adjuntamos a un contenedor y verificamos su persistencia.

Paso 2: creación de un volumen que persiste cuando se elimina el contenedor

En nuestro próximo ejemplo, crearemos un volumen al mismo tiempo que el contenedor, eliminaremos el contenedor y luego adjuntaremos el volumen a un nuevo contenedor.

Utilizaremos el comando run docker para crear un nuevo contenedor utilizando la imagen base de Ubuntu. –t nos dará un terminal e –i nos permitirá interactuar con él. Para mayor claridad, usaremos –name para identificar el contenedor.

El indicador –v nos permitirá crear un nuevo volumen, al que llamaremos DataVolume2. Usaremos dos puntos para separar este nombre de la ruta donde se debe montar el volumen en el contenedor. Por último, vamos a especificar la imagen de Ubuntu base y confiar en el comando por defecto en el docker de Ubuntu. Usaremos bash para utilizar una shell.

Nota:

El indicador -v es muy flexible. Puedes enlazar o nombrar un volumen con solo un ligero ajuste en la sintaxis. Si el primer argumento comienza con a /~/ estás creando un bindmount. Elimina eso y estarás nombrando el volumen. Por ejemplo:

  • -v /path:/path/in/container monta el directorio de host, /path en el /path/in/container
  • -v path:/path/in/container crea un volumen nombrado path sin relación con el host.

Para obtener más información sobre cómo montar un directorio desde el host, puedes consultar cómo compartir datos entre un contenedor Docker y el host.

Mientras estés en el contenedor, escribiremos algunos datos en el volumen:

Salgamos del contenedor:

Cuando reiniciamos el contenedor, el volumen se montará automáticamente:

Verifiquemos que el volumen se haya montado y nuestros datos aún estén en su lugar:

Finalmente, salgamos y limpiemos:

Docker no nos permitirá eliminar un volumen si un contenedor hace referencia a él. Veamos qué sucede cuando intentamos:

El mensaje nos dice que el volumen todavía está en uso y proporciona la versión larga del ID del contenedor:

Podemos usar este ID para eliminar el contenedor:

Remover el contenedor no afectará el volumen. Podemos ver que todavía está presente en el sistema al enumerar los volúmenes con docker volume ls:

Y podemos usar docker volume rm para eliminarlo:

En este ejemplo, creamos un volumen de datos vacío al mismo tiempo que creamos un contenedor. En nuestro próximo ejemplo, exploraremos lo que sucede cuando creamos un volumen con un directorio contenedor que ya contiene datos.

Paso 3: crear un volumen a partir de un directorio existente con datos

Generalmente, crear un volumen independientemente con docker volume create y crear uno mientras se crea un contenedor son equivalentes, con una excepción. Si creamos un volumen al mismo tiempo que creamos un contenedor. Luego proporcionamos la ruta a un directorio que contiene datos en la imagen base, esos datos se copiarán en el volumen.

Como ejemplo, crearemos un contenedor y agregaremos el volumen de datos en /var, un directorio que contiene datos en la imagen base:

Todo el contenido del directorio /var de la imagen base se copia en el volumen, y podemos montar ese volumen en un nuevo contenedor.

Debes salir del contenedor actual:

Esta vez, en lugar de depender del comando bash predeterminado de la imagen base, emitiremos nuestro propio comando ls. Este mostrará el contenido del volumen sin ingresar a la shell:

El directorio datavolume3 ahora tiene una copia de los contenidos del directorio /var de la imagen base:

Es poco probable que queramos montar /var/ de esta manera. Empero esto puede ser útil si hemos creado nuestra propia imagen y queremos una manera fácil de preservar los datos. En nuestro próximo ejemplo, demostraremos cómo se puede compartir un volumen entre varios contenedores.

Paso 4: compartir datos entre múltiples contenedores Docker

Hasta ahora, hemos adjuntado un volumen a un contenedor a la vez. A menudo, queremos que se adjunten varios contenedores al mismo volumen de datos. Esto es relativamente sencillo de lograr, pero hay una advertencia crítica: en este momento, Docker no maneja el bloqueo de archivos. Si necesitas que varios contenedores escriban en el volumen, las aplicaciones que se ejecutan en esos contenedores deben estar diseñadas para escribir en almacenes de datos compartidos. Esto para evitar la corrupción de datos.

Crear Container4 y DataVolume4

Debes usar docker run para crear un nuevo contenedor llamado Container4 con un volumen de datos adjunto:

A continuación, crearemos un archivo y agregaremos texto:

Luego, saldremos del contenedor:

Esto nos devuelve al símbolo del sistema host, donde crearemos un nuevo contenedor desde el que se monta el volumen de datos Container4.

Crear Container5 y montar volúmenes desde Container4

Vamos a crear Container5 y montar los volúmenes desde Container4:

Veamos la persistencia de datos:

Ahora agreguemos un texto de Container5:

Finalmente, saldremos del contenedor:

A continuación, verificaremos que nuestros datos aún estén presentes Container4.

Ver los cambios realizados en Container5

Revisemos los cambios que se escribieron en el volumen de datos Container5 reiniciando Container4:

Verificar los cambios:

Ahora que hemos verificado que ambos contenedores pudieron leer y escribir desde el volumen de datos, saldremos del contenedor:

Nuevamente, Docker no maneja ningún bloqueo de archivos, por lo que las aplicaciones deben tener en cuenta el bloqueo de archivos ellos mismos. Es posible montar un volumen Docker como de solo lectura para garantizar que la corrupción de datos no ocurra por accidente. Esto se puede lograr cuando un contenedor requiera acceso de solo lectura mediante la adición de :ro. Veamos cómo funciona esto.

Iniciar el contenedor 6 y montar el volumen de solo lectura

Una vez que se ha montado un volumen en un contenedor, en lugar de desmontarlo como lo haríamos con un sistema de archivos Linux típico, podemos crear un nuevo contenedor montado de la manera que queramos y, si es necesario, eliminar el contenedor anterior. Para hacer que el volumen sea de solo lectura, agregamos :ro al final del nombre del contenedor:

Verificaremos el estado de solo lectura intentando eliminar nuestro archivo de ejemplo:

Finalmente, saldremos del contenedor y limpiaremos nuestros contenedores y volúmenes de prueba:

Ahora que hemos terminado, limpiemos nuestros contenedores y volumen:

En este ejemplo, mostramos cómo compartir datos entre dos contenedores usando un volumen de datos y cómo montar un volumen de datos como solo lectura.

Conclusión

En este tutorial, creamos un volumen de datos que permitió que los datos persistieran mediante la eliminación de un contenedor. Compartimos volúmenes de datos entre contenedores. Esto con la advertencia de que las aplicaciones deberán diseñarse para manejar el bloqueo de archivos para evitar la corrupción de datos. Finalmente, mostramos cómo montar un volumen compartido en modo de solo lectura.