# Usar bind mounts


En la [parte 4](/get-started/workshop/05_persisting_data/), 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](https://npmjs.com/package/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.

1. Verifica que tu directorio `getting-started-app` se 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](/desktop/settings-and-maintenance/settings/#file-sharing).

     > [!NOTE]
     > La 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.

2. Abre una terminal y cambia al directorio `getting-started-app`.

3. Ejecuta el siguiente comando para iniciar `bash` en un contenedor `ubuntu` con un bind mount.

   **Mac / Linux**



   ```console
   $ docker run -it --mount type=bind,src=.,target=/src ubuntu bash
   ```
   
   **Command Prompt**



   ```console
   $ docker run -it --mount "type=bind,src=%cd%,target=/src" ubuntu bash
   ```
   
   **Git Bash**



   ```console
   $ docker run -it --mount type=bind,src="./",target=/src ubuntu bash
   ```
   
   **PowerShell**



   ```console
   $ docker run -it --mount "type=bind,src=.,target=/src" ubuntu bash
   ```
   
   
   
   La opción `--mount type=bind` le indica a Docker que cree un montaje de tipo bind, donde `src` es el directorio de trabajo actual en tu máquina host (`getting-started-app`), y `target` es donde ese directorio debe aparecer dentro del contenedor (`/src`).

4. Después de ejecutar el comando, Docker inicia una sesión interactiva de `bash` en el directorio raíz del sistema de archivos del contenedor.

   ```console
   root@ac1237fad8db:/# pwd
   /
   root@ac1237fad8db:/# ls
   bin   dev  home  media  opt   root  sbin  srv  tmp  var
   boot  etc  lib   mnt    proc  run   src   sys  usr
   ```

5. Cambia 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-app` de tu máquina host.

   ```console
   root@ac1237fad8db:/# cd src
   root@ac1237fad8db:/src# ls
   Dockerfile  node_modules  package.json  package-lock.json  spec  src  
   ```

6. Crea un nuevo archivo llamado `myfile.txt`.

   ```console
   root@ac1237fad8db:/src# touch myfile.txt
   root@ac1237fad8db:/src# ls
   Dockerfile  myfile.txt  node_modules  package.json  package-lock.json  spec  src  
   ```

7. Abre el directorio `getting-started-app` en el host y observa que el archivo `myfile.txt` se encuentra en el directorio.

   ```text
   ├── getting-started-app/
   │ ├── Dockerfile
   │ ├── myfile.txt
   │ ├── node_modules/
   │ ├── package.json
   │ ├── package-lock.json
   │ ├── spec/
   │ └── src/
   ```

8. Desde el host, elimina el archivo `myfile.txt`.
9. En el contenedor, enumera el contenido del directorio `src` una vez más. Observa que el archivo ya no está.

   ```console
   root@ac1237fad8db:/src# ls
   Dockerfile  node_modules  package.json  package-lock.json spec  src  
   ```

10. Deté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 `nodemon` para vigilar los cambios en el sistema de archivos.

Puedes usar la CLI o Docker Desktop para ejecutar tu contenedor con un bind mount.

**Mac / Linux CLI**



1. Asegúrate de no tener ningún contenedor `getting-started` ejecutándose actualmente.

2. Ejecuta el siguiente comando desde el directorio `getting-started-app`.

   ```console
   $ 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 `/app` del 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 usando `sh` (alpine no tiene `bash`), ejecutando `npm install` para instalar los paquetes y luego ejecutando `npm run dev` para iniciar el servidor de desarrollo. Si observas el archivo `package.json`, verás que el script `dev` inicia `nodemon`.

3. Puedes vigilar los registros utilizando `docker logs <container-id>`. Sabrás que estás listo para comenzar cuando veas esto:

   ```console
   $ 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 3000
   ```

   Cuando hayas terminado de ver los registros, sal presionando `Ctrl`+`C`.

**PowerShell CLI**



1. Asegúrate de no tener ningún contenedor `getting-started` ejecutándose actualmente.

2. Ejecuta el siguiente comando desde el directorio `getting-started-app`.

   ```powershell
   $ 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 `/app` del 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 usando `sh` (alpine no tiene `bash`), ejecutando `npm install` para instalar los paquetes y luego ejecutando `npm run dev` para iniciar el servidor de desarrollo. Si observas el archivo `package.json`, verás que el script `dev` inicia `nodemon`.

3. Puedes vigilar los registros utilizando `docker logs <container-id>`. Sabrás que estás listo para comenzar cuando veas esto:

   ```console
   $ 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 3000
   ```

   Cuando hayas terminado de ver los registros, sal presionando `Ctrl`+`C`.

**Command Prompt CLI**



1. Asegúrate de no tener ningún contenedor `getting-started` ejecutándose actualmente.

2. Ejecuta el siguiente comando desde el directorio `getting-started-app`.

   ```console
   $ 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 `/app` del 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 usando `sh` (alpine no tiene `bash`), ejecutando `npm install` para instalar los paquetes y luego ejecutando `npm run dev` para iniciar el servidor de desarrollo. Si observas el archivo `package.json`, verás que el script `dev` inicia `nodemon`.

3. Puedes vigilar los registros utilizando `docker logs <container-id>`. Sabrás que estás listo para comenzar cuando veas esto:

   ```console
   $ 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 3000
   ```

   Cuando hayas terminado de ver los registros, sal presionando `Ctrl`+`C`.

**Git Bash CLI**



1. Asegúrate de no tener ningún contenedor `getting-started` ejecutándose actualmente.

2. Ejecuta el siguiente comando desde el directorio `getting-started-app`.

   ```console
   $ 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 `/app` del 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 usando `sh` (alpine no tiene `bash`), ejecutando `npm install` para instalar los paquetes y luego ejecutando `npm run dev` para iniciar el servidor de desarrollo. Si observas el archivo `package.json`, verás que el script `dev` inicia `nodemon`.

3. Puedes vigilar los registros utilizando `docker logs <container-id>`. Sabrás que estás listo para comenzar cuando veas esto:

   ```console
   $ 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 3000
   ```

   Cuando hayas terminado de ver los registros, sal presionando `Ctrl`+`C`.

**Docker Desktop**



Asegúrate de no tener ningún contenedor `getting-started` ejecutándose actualmente.

Ejecuta la imagen con un bind mount.

1. Selecciona el cuadro de búsqueda en la parte superior de Docker Desktop.
2. En la ventana de búsqueda, selecciona la pestaña **Images**.
3. En el cuadro de búsqueda, especifica el nombre del contenedor: `getting-started`.

   > [!TIP]
   >
   > Utiliza el filtro de búsqueda para filtrar las imágenes y mostrar únicamente **Local images** (Imágenes locales).

4. Selecciona tu imagen y luego selecciona **Run**.
5. Selecciona **Optional settings**.
6. En **Host path**, especifica la ruta al directorio `getting-started-app` en tu máquina host.
7. En **Container path**, especifica `/app`.
8. Selecciona **Run**.

Puedes vigilar los registros del contenedor utilizando Docker Desktop.

1. Selecciona **Containers** en Docker Desktop.
2. Selecciona el nombre de tu contenedor.

Sabrás que estás listo para comenzar cuando veas esto:

```console
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.

1. En el archivo `src/static/js/app.js`, en la línea 109, cambia el botón "Add Item" para que simplemente diga "Add":

   ```diff
   - {submitting ? 'Adding...' : 'Add Item'}
   + {submitting ? 'Adding...' : 'Add'}
   ```

   Guarda el archivo.

2. 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.

   ![Captura de pantalla de la etiqueta actualizada para el botón Add](/get-started/workshop/06_bind_mounts/images/updated-add-button.webp)

3. 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:

   ```console
   $ 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:

 - [Referencia de la CLI de Docker](/reference/cli/docker/)
 - [Gestionar datos en Docker](https://docs-docker.esdocu.com/storage/)

## 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](/get-started/workshop/06_bind_mounts/07_multi_container/)



