Usar bind mounts
En la parte 4, utilizaste un montaje de volumen para persistir los datos de tu base de datos. Un montaje de volumen es una excelente opción cuando necesitas un lugar persistente para almacenar los datos de tu aplicación.
Un montaje de tipo bind (bind mount) es otro tipo de montaje que te permite compartir un directorio del sistema de archivos del host dentro del contenedor. Al trabajar en una aplicación, puedes usar un bind mount para montar el código fuente dentro del contenedor. El contenedor ve los cambios que realizas en el código de inmediato, tan pronto como guardas un archivo. Esto significa que puedes ejecutar procesos en el contenedor que vigilen los cambios en el sistema de archivos y respondan a ellos.
En este capítulo, verás cómo puedes usar bind mounts y una herramienta llamada nodemon para vigilar los cambios de archivos y luego reiniciar la aplicación automáticamente. Existen herramientas equivalentes en la mayoría de los demás lenguajes y frameworks.
Comparaciones rápidas de tipos de volumen
A continuación se muestran ejemplos de un volumen con nombre y un bind mount utilizando --mount:
- Volumen con nombre:
type=volume,src=my-volume,target=/usr/local/data - Bind mount (montaje de tipo bind):
type=bind,src=/path/to/data,target=/usr/local/data
La siguiente tabla resume las diferencias principales entre los montajes de volumen y los bind mounts.
| Volúmenes con nombre | Bind mounts | |
|---|---|---|
| Ubicación en el host | Docker elige | Tú decides |
| Llena el nuevo volumen con el contenido del contenedor | Sí | No |
| Soporta controladores de volumen (Volume Drivers) | Sí | No |
Probar los bind mounts
Antes de analizar cómo puedes usar los bind mounts para desarrollar tu aplicación, puedes realizar un experimento rápido para comprender de manera práctica cómo funcionan.
Verifica que tu directorio
getting-started-appse encuentre en un directorio definido en la configuración de uso compartido de archivos (file sharing) de Docker Desktop. Esta configuración define qué partes de tu sistema de archivos puedes compartir con los contenedores. Para obtener detalles sobre cómo acceder a esta configuración, consulta Uso compartido de archivos.NoteLa pestaña File sharing solo está disponible en el modo Hyper-V, ya que los archivos se comparten automáticamente en el modo WSL 2 y en el modo de contenedor de Windows.
Abre una terminal y cambia al directorio
getting-started-app.Ejecuta el siguiente comando para iniciar
bashen un contenedorubuntucon un bind mount.$ docker run -it --mount type=bind,src=.,target=/src ubuntu bash$ docker run -it --mount "type=bind,src=%cd%,target=/src" ubuntu bash$ docker run -it --mount type=bind,src="./",target=/src ubuntu bash$ docker run -it --mount "type=bind,src=.,target=/src" ubuntu bashLa opción
--mount type=bindle indica a Docker que cree un montaje de tipo bind, dondesrces el directorio de trabajo actual en tu máquina host (getting-started-app), ytargetes donde ese directorio debe aparecer dentro del contenedor (/src).Después de ejecutar el comando, Docker inicia una sesión interactiva de
bashen el directorio raíz del sistema de archivos del contenedor.root@ac1237fad8db:/# pwd / root@ac1237fad8db:/# ls bin dev home media opt root sbin srv tmp var boot etc lib mnt proc run src sys usrCambia al directorio
src.Este es el directorio que montaste al iniciar el contenedor. Al enumerar el contenido de este directorio, se muestran los mismos archivos que en el directorio
getting-started-appde tu máquina host.root@ac1237fad8db:/# cd src root@ac1237fad8db:/src# ls Dockerfile node_modules package.json package-lock.json spec srcCrea un nuevo archivo llamado
myfile.txt.root@ac1237fad8db:/src# touch myfile.txt root@ac1237fad8db:/src# ls Dockerfile myfile.txt node_modules package.json package-lock.json spec srcAbre el directorio
getting-started-appen el host y observa que el archivomyfile.txtse encuentra en el directorio.├── getting-started-app/ │ ├── Dockerfile │ ├── myfile.txt │ ├── node_modules/ │ ├── package.json │ ├── package-lock.json │ ├── spec/ │ └── src/Desde el host, elimina el archivo
myfile.txt.En el contenedor, enumera el contenido del directorio
srcuna vez más. Observa que el archivo ya no está.root@ac1237fad8db:/src# ls Dockerfile node_modules package.json package-lock.json spec srcDetén la sesión interactiva del contenedor con
Ctrl+D.
Eso es todo para una breve introducción a los bind mounts. Este procedimiento demostró cómo se comparten los archivos entre el host y el contenedor, y cómo los cambios se reflejan inmediatamente en ambos lados. Ahora puedes usar bind mounts para desarrollar software.
Contenedores de desarrollo
El uso de bind mounts es común para entornos de desarrollo local. La ventaja es que la máquina de desarrollo no necesita tener instaladas todas las herramientas y entornos de compilación. Con un solo comando docker run, Docker descarga las dependencias y herramientas.
Ejecutar tu aplicación en un contenedor de desarrollo
Los siguientes pasos describen cómo ejecutar un contenedor de desarrollo con un bind mount que realiza lo siguiente:
- Monta tu código fuente en el contenedor.
- Instala todas las dependencias.
- Inicia
nodemonpara vigilar los cambios en el sistema de archivos.
Puedes usar la CLI o Docker Desktop para ejecutar tu contenedor con un bind mount.
Asegúrate de no tener ningún contenedor
getting-startedejecutándose actualmente.Ejecuta el siguiente comando desde el directorio
getting-started-app.$ docker run -dp 127.0.0.1:3000:3000 \ -w /app --mount type=bind,src=.,target=/app \ node:24-alpine \ sh -c "npm install && npm run dev"A continuación se presenta un desglose del comando:
-dp 127.0.0.1:3000:3000: igual que antes. Se ejecuta en modo desasociado (segundo plano) y crea un mapeo de puertos.-w /app: establece el "directorio de trabajo" o el directorio actual desde el cual se ejecutará el comando.--mount type=bind,src=.,target=/app: realiza un montaje de tipo bind del directorio actual del host en el directorio/appdel contenedor.node:24-alpine: la imagen que se va a utilizar. Ten en cuenta que esta es la imagen base para tu aplicación definida en el Dockerfile.sh -c "npm install && npm run dev": el comando. Estás iniciando un shell usandosh(alpine no tienebash), ejecutandonpm installpara instalar los paquetes y luego ejecutandonpm run devpara iniciar el servidor de desarrollo. Si observas el archivopackage.json, verás que el scriptdevinicianodemon.
Puedes vigilar los registros utilizando
docker logs <container-id>. Sabrás que estás listo para comenzar cuando veas esto:$ docker logs -f <container-id> nodemon -L src/index.js [nodemon] 2.0.20 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node src/index.js` Using sqlite database at /etc/todos/todo.db Listening on port 3000Cuando hayas terminado de ver los registros, sal presionando
Ctrl+C.
Asegúrate de no tener ningún contenedor
getting-startedejecutándose actualmente.Ejecuta el siguiente comando desde el directorio
getting-started-app.$ docker run -dp 127.0.0.1:3000:3000 ` -w /app --mount "type=bind,src=.,target=/app" ` node:24-alpine ` sh -c "npm install && npm run dev"A continuación se presenta un desglose del comando:
-dp 127.0.0.1:3000:3000: igual que antes. Se ejecuta en modo desasociado (segundo plano) y crea un mapeo de puertos.-w /app: establece el "directorio de trabajo" o el directorio actual desde el cual se ejecutará el comando.--mount "type=bind,src=.,target=/app": realiza un montaje de tipo bind del directorio actual del host en el directorio/appdel contenedor.node:24-alpine: la imagen que se va a utilizar. Ten en cuenta que esta es la imagen base para tu aplicación definida en el Dockerfile.sh -c "npm install && npm run dev": el comando. Estás iniciando un shell usandosh(alpine no tienebash), ejecutandonpm installpara instalar los paquetes y luego ejecutandonpm run devpara iniciar el servidor de desarrollo. Si observas el archivopackage.json, verás que el scriptdevinicianodemon.
Puedes vigilar los registros utilizando
docker logs <container-id>. Sabrás que estás listo para comenzar cuando veas esto:$ docker logs -f <container-id> nodemon -L src/index.js [nodemon] 2.0.20 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node src/index.js` Using sqlite database at /etc/todos/todo.db Listening on port 3000Cuando hayas terminado de ver los registros, sal presionando
Ctrl+C.
Asegúrate de no tener ningún contenedor
getting-startedejecutándose actualmente.Ejecuta el siguiente comando desde el directorio
getting-started-app.$ docker run -dp 127.0.0.1:3000:3000 ^ -w /app --mount "type=bind,src=%cd%,target=/app" ^ node:24-alpine ^ sh -c "npm install && npm run dev"A continuación se presenta un desglose del comando:
-dp 127.0.0.1:3000:3000: igual que antes. Se ejecuta en modo desasociado (segundo plano) y crea un mapeo de puertos.-w /app: establece el "directorio de trabajo" o el directorio actual desde el cual se ejecutará el comando.--mount "type=bind,src=%cd%,target=/app": realiza un montaje de tipo bind del directorio actual del host en el directorio/appdel contenedor.node:24-alpine: la imagen que se va a utilizar. Ten en cuenta que esta es la imagen base para tu aplicación definida en el Dockerfile.sh -c "npm install && npm run dev": el comando. Estás iniciando un shell usandosh(alpine no tienebash), ejecutandonpm installpara instalar los paquetes y luego ejecutandonpm run devpara iniciar el servidor de desarrollo. Si observas el archivopackage.json, verás que el scriptdevinicianodemon.
Puedes vigilar los registros utilizando
docker logs <container-id>. Sabrás que estás listo para comenzar cuando veas esto:$ docker logs -f <container-id> nodemon -L src/index.js [nodemon] 2.0.20 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node src/index.js` Using sqlite database at /etc/todos/todo.db Listening on port 3000Cuando hayas terminado de ver los registros, sal presionando
Ctrl+C.
Asegúrate de no tener ningún contenedor
getting-startedejecutándose actualmente.Ejecuta el siguiente comando desde el directorio
getting-started-app.$ docker run -dp 127.0.0.1:3000:3000 \ -w //app --mount type=bind,src="./",target=/app \ node:24-alpine \ sh -c "npm install && npm run dev"A continuación se presenta un desglose del comando:
-dp 127.0.0.1:3000:3000: igual que antes. Se ejecuta en modo desasociado (segundo plano) y crea un mapeo de puertos.-w //app: establece el "directorio de trabajo" o el directorio actual desde el cual se ejecutará el comando.--mount type=bind,src="/.",target=/app: realiza un montaje de tipo bind del directorio actual del host en el directorio/appdel contenedor.node:24-alpine: la imagen que se va a utilizar. Ten en cuenta que esta es la imagen base para tu aplicación definida en el Dockerfile.sh -c "npm install && npm run dev": el comando. Estás iniciando un shell usandosh(alpine no tienebash), ejecutandonpm installpara instalar los paquetes y luego ejecutandonpm run devpara iniciar el servidor de desarrollo. Si observas el archivopackage.json, verás que el scriptdevinicianodemon.
Puedes vigilar los registros utilizando
docker logs <container-id>. Sabrás que estás listo para comenzar cuando veas esto:$ docker logs -f <container-id> nodemon -L src/index.js [nodemon] 2.0.20 [nodemon] to restart at any time, enter `rs` [nodemon] watching path(s): *.* [nodemon] watching extensions: js,mjs,json [nodemon] starting `node src/index.js` Using sqlite database at /etc/todos/todo.db Listening on port 3000Cuando hayas terminado de ver los registros, sal presionando
Ctrl+C.
Asegúrate de no tener ningún contenedor getting-started ejecutándose actualmente.
Ejecuta la imagen con un bind mount.
Selecciona el cuadro de búsqueda en la parte superior de Docker Desktop.
En la ventana de búsqueda, selecciona la pestaña Images.
En el cuadro de búsqueda, especifica el nombre del contenedor:
getting-started.TipUtiliza el filtro de búsqueda para filtrar las imágenes y mostrar únicamente Local images (Imágenes locales).
Selecciona tu imagen y luego selecciona Run.
Selecciona Optional settings.
En Host path, especifica la ruta al directorio
getting-started-appen tu máquina host.En Container path, especifica
/app.Selecciona Run.
Puedes vigilar los registros del contenedor utilizando Docker Desktop.
- Selecciona Containers en Docker Desktop.
- Selecciona el nombre de tu contenedor.
Sabrás que estás listo para comenzar cuando veas esto:
nodemon -L src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000
Desarrollar tu aplicación con el contenedor de desarrollo
Actualiza tu aplicación en tu máquina host y observa los cambios reflejados en el contenedor.
En el archivo
src/static/js/app.js, en la línea 109, cambia el botón "Add Item" para que simplemente diga "Add":- {submitting ? 'Adding...' : 'Add Item'} + {submitting ? 'Adding...' : 'Add'}Guarda el archivo.
Actualiza la página en tu navegador web y deberías ver el cambio reflejado casi de inmediato debido al bind mount. Nodemon detecta el cambio y reinicia el servidor. Puede tomar unos segundos para que el servidor de Node se reinicie. Si obtienes un error, intenta actualizar después de unos segundos.

Siéntete libre de realizar cualquier otro cambio que desees. Cada vez que realizas un cambio y guardas un archivo, el cambio se refleja en el contenedor debido al bind mount. Cuando Nodemon detecta un cambio, reinicia automáticamente la aplicación dentro del contenedor. Cuando hayas terminado, detén el contenedor y compila tu nueva imagen utilizando:
$ docker build -t getting-started .
Resumen
En este punto, puedes persistir tu base de datos y ver los cambios en tu aplicación a medida que la desarrollas sin tener que volver a compilar la imagen.
Además de los montajes de volumen y los bind mounts, Docker también admite otros tipos de montajes y controladores de almacenamiento para manejar casos de uso más complejos y especializados.
Información relacionada:
Siguientes pasos
Para preparar tu aplicación para producción, debes migrar tu base de datos SQLite a algo que pueda escalar un poco mejor. Por simplicidad, seguirás utilizando una base de datos relacional y cambiarás tu aplicación para usar MySQL. But, ¿cómo deberías ejecutar MySQL? ¿Cómo permites que los contenedores se comuniquen entre si? Aprenderás sobre esto en la siguiente sección.
Aplicaciones multicontenedor