Docker: la verdadera diferencia entre volumes y bind mounts

Guido Collino
Unagi
Published in
5 min readJan 23, 2023

Docker es una de la herramientas que más creció en los últimos años y no es casualidad, ya qué viene a simplificar la creación, prueba y despliegue de nuestras aplicaciones. Nos da un receta que podemos llevar a cualquier servidor o máquina con cualquier sistema operativo y desplegar nuestro stack corriendo un único comando.

En Unagi hace tiempo lo estamos usando y nos cambió la vida, bueno tal vez esté exagerando, pero sí nos ahorra mucho tiempo y cómo bien dice el dicho: “el tiempo es dinero”.

En todas nuestras aplicaciones configuramos docker y docker-compose para que los desarrolladores puedan correr los test y la aplicación de una forma simple. No solo corre la aplicación, sino todos los servicios necesarios, como puede ser postgres, redis o selenium en el caso de system tests.

Dockerizar nuestra aplicación no solo tiene beneficios en la etapa de desarrollo de una aplicación, sino que nos simplifica el despliegue de distintos ambientes (staging, pre-producción y producción) en muchas de las plataformas que conocemos, como AWS, DigitalOcean, Heroku, etc.

Sumado que es casi indispensable para poder implementar integración continua. En nuestro caso, los usamos para hacer integración continua con GitHub Actions y GitLab CI.

Almacenamiento

Por defecto, la información generada por un contenedor de docker se guarda en una capa de escritura. Esto tiene sus ventajas, pero es importante tener en cuenta que tiene las siguientes contras:

  • Los datos no se persisten. Eso quiere decir que si tu docker se apaga, muere o es abducido por un ser extraterreste, tus datos se pierden.
  • La capa de escritura está estrechamente acoplada al host donde está corriendo tu contenedor. Esto complica la posibilidad de mover la información a otro lugar.
  • Es necesario un driver para manejar el filesystem, impactando en la performance.

Docker tiene 2 opciones de almacenamiento para manejar la persistencia de datos: volúmenes y bind mounts.

Volúmenes

Se guardan en una parte del filesystem que es manejada por Docker. Ningún proceso fuera de Docker tiene permisos para modificar esta parte del filesystem.

Los volúmenes se pueden crear usando Docker a través del comando:

El comando crea un directorio en el host y luego se monta dentro de un contenedor.

Un volumen puede ser montado en varios contenedores, lo que lo hace muy útil para compartir datos entre contenedores.

Los volúmenes que no están siendo usados por ningún contenedor no se borran automáticamente. Para hacerlo debemos ejecutar el siguiente comando:

Los volúmenes se pueden nombrar o ser anónimos. En el caso de no asignar un nombre a un volumen, Docker asigna un nombre único de forma aleatoria.
El nombrado simplemente permite una mejor organización de nuestros volúmenes, ya que no modifica su funcionamiento.

Bind mounts

Una de las ventajas de bind mounts es que se puede guardar en cualquier lugar del filesystem del host. A diferencia de los volúmenes estos sí pueden ser modificados por un proceso fuera de docker.

Fue el primer tipo de almacenamiento que tuvo Docker y por esto es que tiene ciertas limitaciones en comparación con volúmenes.

Cuando usamos bind mounts lo que estamos haciendo es montar un archivo o directorio del host dentro de nuestro contenedor.

Esto lo hace muy performante, pero no deja de ser un archivo o directorio en nuestro host, que puede ser modificado por cualquier usuario o proceso.

Ahora bien, ya sé que es cada uno pero… ¿cuándo me conviene usar cada uno?

Volúmenes

  • Compartir datos entre contenedores.
  • Cuando no sabemos si el host va tener tener determinado directorio o estructura de archivos. Los volúmenes nos permiten desacoplar la configuración del host de nuestros contenedores.
  • Cuando queremos tener nuestros datos en un host remoto o cloud.
  • Para hacer backup y restore de los datos entre distintos hosts.
  • Para tener mejor performance. Los volúmenes tienen mejor latencia y rendimiento que el almacenamiento por defecto de los contenedores. Independientemente de que no necesitemos persistir los datos.

Bind mounts

  • Compartir archivos de configuración entre el host y los contenedores.
  • Compartir el código fuente de una aplicación en un entorno de desarrollo. Nos va permitir por ejemplo poder hacer modificaciones desde nuestro editor y ver los cambios en el contenedor sin tener que reiniciar el contenedor.

Bind mount y volúmenes en contenedores

Para definir un bind mount o montar un volumen en un contenedor se debe agregar el flag -v o — mount al comando run. Veamos algunos ejemplos:

  • Montar un volumen de lectura/escritura:

myDatabases: el nombre del volumen
/var/lib/mysql: el directorio donde vamos a montar el volumen en el contendor

  • Montar un volumen solo lectura

Uso en docker-compose

Como sabemos docker-compose nos permite definir nuestros contenedores a través de un archivo de configuración. Vamos a ver cómo podemos definir volúmenes y montarlos dentro de los contenedores:

Para que un servicio definido en nuestro docker-compose use un volumen es necesario definir la opción volumes dentro del servicio como se muestra en el ejemplo previo.

En el caso que se quiera definir configuraciones para ese volumen, como el driver por ejemplo, es necesario agregar la opción volumes al mismo nivel que services y definir nuestro volumen. También es necesario definir el volumen fuera del servicio si se va a compartir entre diferentes servicios como se muestra en el siguiente ejemplo:

También es posible crear los volúmenes fuera de nuestro docker-compose, por ejemplo para cuando se va compartir entre diferentes contenedores o ya teníamos creado el volumen en otro lado. Hay que agregar la opción external: true en la definición del volumen:

Si el volumen no existe nos va pedir que corramos el comando para crearlo.

Trucos y Consejos

  • Si montamos un volumen en un directorio de un contenedor, el cual tiene archivos y/o directorios, estos se van a copiar en el volumen ni bien se instancia el contendor. Esto puede ser útil para que un contendor le precargue datos a otro contenedor.
  • Si montamos un bind–mount o volumen vacío en un directorio de contenedor que ya contiene directorios y/o archivos, estos van a ser oscurecidos, es decir, no se pierde o cambia la información pero no podrán ser accedidos mientras el volumen esté montado.

--

--