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

Usar Compose Watch

Requiere: Docker Compose 2.22.0 y posterior

El atributo watch actualiza y previsualiza automáticamente tus servicios de Compose en ejecución a medida que editas y guardas tu código. En muchos proyectos, esto facilita un flujo de trabajo de desarrollo desatendido una vez que Compose se está ejecutando, ya que los servicios se actualizan automáticamente cuando guardas tu trabajo.

watch se rige por las siguientes reglas para las rutas de archivos:

  • Todas las rutas son relativas al directorio del proyecto, excepto los patrones del archivo de exclusión (ignore).
  • Los directorios se observan de forma recursiva.
  • No se admiten patrones glob.
  • Se aplican las reglas de .dockerignore.
    • Utiliza la opción ignore para definir rutas adicionales a ignorar (misma sintaxis).
    • Los archivos temporales/de respaldo de los IDE comunes (Vim, Emacs, JetBrains y otros) se ignoran automáticamente.
    • Los directorios .git se ignoran automáticamente.

No necesitas activar watch para todos los servicios de un proyecto de Compose. En algunos casos, solo una parte del proyecto, por ejemplo el frontend en JavaScript, puede ser adecuada para las actualizaciones automáticas.

Compose Watch está diseñado para funcionar con servicios compilados a partir de código fuente local utilizando el atributo build. No realiza un seguimiento de los cambios en los servicios que dependen de imágenes precompiladas especificadas por el atributo image.

Compose Watch frente a los montajes de vinculación (bind mounts)

Compose admite compartir un directorio del host dentro de los contenedores de los servicios. El modo de observación (watch) no reemplaza esta funcionalidad, sino que existe como un complemento específicamente diseñado para el desarrollo en contenedores.

Más importante aún, watch permite una mayor granularidad de la que es práctica con un montaje de vinculación. Las reglas de observación te permiten ignorar archivos específicos o directorios enteros dentro del árbol observado.

Por ejemplo, en un proyecto de JavaScript, ignorar el directorio node_modules/ tiene dos ventajas:

  • Rendimiento: los árboles de archivos con muchos archivos pequeños pueden causar una alta carga de E/S en algunas configuraciones.
  • Multiplataforma: los artefactos compilados no se pueden compartir si el sistema operativo host o la arquitectura son diferentes a los del contenedor.

Por ejemplo, en un proyecto de Node.js, no se recomienda sincronizar el directorio node_modules/. Aunque JavaScript es interpretado, los paquetes de npm pueden contener código nativo que no es portable entre plataformas.

Configuración

El atributo watch define una lista de reglas que controlan las actualizaciones automáticas del servicio en función de los cambios en los archivos locales.

Cada regla requiere un patrón de ruta (path) y una acción (action) a realizar cuando se detecta una modificación. Existen dos acciones posibles para watch y, dependiendo de la acción, se podrían admitir o requerir campos adicionales.

El modo de observación se puede utilizar con muchos lenguajes y frameworks diferentes. Las rutas y reglas específicas variarán de un proyecto a otro, pero los conceptos siguen siendo los mismos.

Requisitos previos

Para funcionar correctamente, watch depende de ejecutables comunes. Asegúrate de que la imagen de tu servicio contenga los siguientes binarios:

  • stat
  • mkdir
  • rmdir

watch también requiere que el usuario (USER) del contenedor pueda escribir en la ruta de destino para que pueda actualizar los archivos. Un patrón común es que el contenido inicial se copie en el contenedor mediante la instrucción COPY en un Dockerfile. Para garantizar que dichos archivos pertenezcan al usuario configurado, utiliza la bandera COPY --chown:

# Ejecutar como usuario no privilegiado
FROM node:18
RUN useradd -ms /bin/sh -u 1001 app
USER app

# Instalar dependencias
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install

# Copiar archivos fuente en el directorio de la aplicación
COPY --chown=app:app . /app

action

Sincronización (Sync)

Si la acción (action) está configurada en sync, Compose se asegura de que cualquier cambio realizado en los archivos de tu host coincida automáticamente con los archivos correspondientes dentro del contenedor del servicio.

sync es ideal para frameworks que admiten "Hot Reload" (recarga en caliente) o funcionalidad equivalente.

De manera más general, las reglas de sync se pueden utilizar en lugar de los montajes de vinculación para muchos casos de uso de desarrollo.

Recompilación (Rebuild)

Si la acción está configurada en rebuild, Compose compila automáticamente una nueva imagen con BuildKit y reemplaza el contenedor del servicio en ejecución.

El comportamiento es el mismo que ejecutar docker compose up --build <servicio>.

La recompilación es ideal para lenguajes compilados o como alternativa para modificaciones en archivos particulares que requieren una reconstrucción completa de la imagen (por ejemplo, package.json).

Sincronización y reinicio (Sync + Restart)

Si la acción está configurada en sync+restart, Compose sincroniza tus cambios con los contenedores del servicio y los reinicia.

sync+restart resulta ideal cuando cambia el archivo de configuración y no necesitas compilar la imagen de nuevo, sino únicamente reiniciar el proceso principal de los contenedores del servicio. Funcionará bien cuando actualices una configuración de base de datos o tu archivo nginx.conf, por ejemplo.

Tip

Optimiza tu Dockerfile para realizar recompilaciones incrementales rápidas con el almacenamiento en caché de capas de imagen y compilaciones multi-etapa.

path y target

El campo target controla cómo se mapea la ruta dentro del contenedor.

Para path: ./app/html y un cambio en ./app/html/index.html:

  • target: /app/html -> /app/html/index.html
  • target: /app/static -> /app/static/index.html
  • target: /assets -> /assets/index.html

ignore

Los patrones de ignore son relativos a la ruta (path) definida en la acción watch actual, no al directorio del proyecto. En el siguiente Ejemplo 1, la ruta de exclusión sería relativa al directorio ./web especificado en el atributo path.

initial_sync

Al utilizar una acción sync+x, el atributo initial_sync le indica a Compose que se asegure de que los archivos que forman parte de la ruta (path) definida estén actualizados antes de iniciar una nueva sesión de observación.

Ejemplo 1

Este ejemplo mínimo está dirigido a una aplicación Node.js con la siguiente estructura:

myproject/
├── web/
│   ├── App.jsx
│   ├── index.js
│   └── node_modules/
├── Dockerfile
├── compose.yaml
└── package.json
services:
  web:
    build: .
    command: npm start
    develop:
      watch:
        - action: sync
          path: ./web
          target: /src/web
          initial_sync: true
          ignore:
            - node_modules/
        - action: rebuild
          path: package.json

En este ejemplo, al ejecutar docker compose up --watch, se inicia un contenedor para el servicio web utilizando una imagen compilada a partir del Dockerfile en la raíz del proyecto. El servicio web ejecuta npm start como su comando, lo que inicia una versión de desarrollo de la aplicación con Hot Module Reload habilitado en el empaquetador (Webpack, Vite, Turbopack, etc.).

Una vez que el servicio está en funcionamiento, el modo de observación comienza a monitorear los directorios y archivos de destino. Luego, cada vez que se modifica un archivo fuente en el directorio web/, Compose sincroniza el archivo en la ubicación correspondiente bajo /src/web dentro del contenedor. Por ejemplo, ./web/App.jsx se copia a /src/web/App.jsx.

Una vez copiado, el empaquetador actualiza la aplicación en ejecución sin necesidad de reiniciar.

Y en este caso, la regla ignore se aplicaría a myproject/web/node_modules/, no a myproject/node_modules/.

A diferencia de los archivos de código fuente, añadir una nueva dependencia no se puede hacer sobre la marcha, por lo que cada vez que se modifica package.json, Compose vuelve a compilar la imagen y recrea el contenedor del servicio web.

Este patrón se puede seguir para muchos laenguajes y frameworks, como Python con Flask: los archivos fuente de Python se pueden sincronizar mientras que un cambio en requirements.txt debería activar una recompilación.

Ejemplo 2

Adaptando el ejemplo anterior para demostrar sync+restart:

services:
  web:
    build: .
    command: npm start
    develop:
      watch:
        - action: sync
          path: ./web
          target: /app/web
          ignore:
            - node_modules/
        - action: sync+restart
          path: ./proxy/nginx.conf
          target: /etc/nginx/conf.d/default.conf

  backend:
    build:
      context: backend
      target: builder

Esta configuración demuestra cómo utilizar la acción sync+restart en Docker Compose para desarrollar y probar de manera eficiente una aplicación Node.js con un servidor web frontend y un servicio backend. La configuración garantiza que los cambios en el código de la aplicación y en los archivos de configuración se sincronicen y apliquen rápidamente, reiniciando el servicio web según sea necesario para reflejar los cambios.

Usa watch

  1. Añade secciones watch a uno o más servicios en compose.yaml.
  2. Ejecuta docker compose up --watch para construir e iniciar un proyecto de Compose y arrancar el modo de vigilancia de archivos.
  3. Edita los archivos fuente del servicio utilizando tu IDE o editor preferido.
Note

Watch también se puede utilizar con el comando dedicado docker compose watch si no deseas que los registros (logs) de la aplicación se mezclen con los registros de (re)compilación y los eventos de sincronización del sistema de archivos.

Tip

Consulta dockersamples/avatars o la configuración local para la documentación de Docker para ver una demostración de Compose watch.

Referencia