Compartir comentarios
Las respuestas se generan en base a la documentación.

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 nombreBind mounts
Ubicación en el hostDocker eligeTú decides
Llena el nuevo volumen con el contenido del contenedorNo
Soporta controladores de volumen (Volume Drivers)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.

    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.

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

    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.

    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.

    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.

    ├── 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á.

    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.

  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.

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

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

  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.

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

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

  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.

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

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

  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.

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

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

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:

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":

    - {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
  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:

    $ 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