使用 Compose Watch

在 Docker Compose 版本中引入 2.22.0

watch 属性会在您编辑并保存代码时,自动更新并预览正在运行的 Compose 服务。对于许多项目而言,一旦 Compose 启动,这便实现了无需手动干预的开发工作流程,因为当您保存工作成果时,服务会自动完成更新。

watch 遵循以下文件路径规则:

  • 所有路径均相对于项目目录
  • 目录将被递归监控
  • 不支持通配符模式
  • 来自 .dockerignore 的规则适用
    • 使用 ignore 选项定义要忽略的额外路径(语法相同)
    • 常见 IDE(Vim、Emacs、JetBrains 等)的临时/备份文件将自动被忽略
    • .git 目录将自动被忽略

您无需为 Compose 项目中的所有服务开启 watch。在某些情况下,仅项目的部分组件(例如 JavaScript 前端)可能适合自动更新。

Compose Watch 旨在与使用 build 属性从本地源代码构建的服务配合使用。它不会跟踪依赖由 image 属性指定的预构建镜像的服务的变更。

Compose Watch 与绑定挂载的对比

Compose 支持在服务容器内共享主机目录。监视模式并非取代此功能,而是作为专为在容器中进行开发而设计的辅助功能存在。

更重要的是,watch 提供了比绑定挂载更实用的细粒度控制。监视规则允许您忽略被监视树中的特定文件或整个目录。

例如,在 JavaScript 项目中,忽略 node_modules/ 目录有两个好处:

  • 性能。包含许多小文件的文件树在某些配置中可能导致高 I/O 负载
  • 多平台。如果主机操作系统或架构与容器不同,则无法共享编译后的工件。

例如,在 Node.js 项目中,不建议同步 node_modules/ 目录。即使 JavaScript 是解释型语言,npm 包也可能包含无法跨平台移植的原生代码。

配置

watch 属性定义了一系列规则,用于根据本地文件变更控制服务的自动更新。

每条规则都需要一个 path 模式,并在检测到修改时采取 action 操作。watch 有两种可能的操作,具体取决于 action,可能会接受或要求其他字段。

监视模式可用于多种不同的语言和框架。 具体路径和规则因项目而异,但核心概念保持不变。

前提条件

为了正常工作,watch 依赖于常见的可执行文件。请确保您的服务镜像包含以下Binaries:

  • 状态
  • mkdir
  • 删除目录

watch 还要求容器的 USER 能够写入目标路径,以便更新文件。一种常见的模式是使用 Dockerfile 中的 COPY 指令将初始内容复制到容器中。为确保此类文件由配置的用户拥有,请使用 COPY --chown 标志:

# Run as a non-privileged user
FROM node:18
RUN useradd -ms /bin/sh -u 1001 app
USER app

# Install dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install

# Copy source files into application directory
COPY --chown=app:app . /app

action

同步

如果将 action 设置为 sync,Compose 会确保您在主机上对文件所做的任何更改自动与服务容器内的相应文件保持同步。

sync 适用于支持“热重载”或等效功能的框架。

更一般地说,在许多开发用例中,可以使用 sync 规则来替代绑定挂载。

重建

如果将 action 设置为 rebuild,Compose 将使用 BuildKit 自动构建新镜像,并替换正在运行的服务容器。

行为与运行 docker compose up --build <svc> 相同。

重新构建非常适合编译型语言,或作为对需要完全镜像重建的特定文件进行修改时的备用方案(例如 package.json)。

同步 + 重启

如果将 action 设置为 sync+restart,Compose 会将您的更改同步到服务容器并重启它。

sync+restart 在配置文件发生更改时最为理想,此时您无需重新构建镜像,只需重启服务容器的主进程即可。 例如,当您更新数据库配置或您的 nginx.conf 文件时,此方法非常适用。

提示

通过镜像层缓存多阶段构建,优化您的Dockerfile以实现快速的增量重建。

pathtarget

target 字段控制路径如何映射到容器中。

对于 path: ./app/html 并更改为 ./app/html/index.html

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

示例 1

此最小示例针对具有以下结构的 Node.js 应用程序:

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

在此示例中,运行 docker compose up --watch 时,将使用从项目根目录中的 Dockerfile 构建的镜像启动 web 服务的容器。 web 服务将其命令设置为运行 npm start,随后在打包工具(如 Webpack、Vite、Turbopack 等)中启用热模块替换(Hot Module Reload),从而启动应用程序的开发版本。

服务启动后,监视模式将开始监控目标目录和文件。 随后,每当 web/ 目录中的源文件发生更改时,Compose 会将该文件同步到容器内 /src/web 下的对应位置。 例如,./web/App.jsx 将被复制到 /src/web/App.jsx

复制完成后,打包工具会在不重启的情况下更新正在运行的应用程序。

与源代码文件不同,添加新依赖无法动态完成,因此每当 package.json 发生更改时,Compose 会重新构建镜像并重建 web 服务容器。

此模式可适用于多种语言和框架,例如使用 Flask 的 Python:Python 源文件可以同步,而对 requirements.txt 的更改应触发重新构建。

示例 2

调整前面的示例以演示 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

此设置演示了如何在 Docker Compose 中使用 sync+restart 操作,以高效开发和测试带有前端 Web 服务器和后端服务的 Node.js 应用程序。该配置确保对应用程序代码和配置文件的更改能够快速同步并应用,同时 web 服务会根据需要重启以反映这些更改。

使用 watch

  1. compose.yaml 中的一个或多个服务添加 watch 个部分。
  2. 运行 docker compose up --watch 以构建并启动 Compose 项目,同时开启文件监听模式。
  3. 使用您首选的 IDE 或编辑器编辑服务源文件。

注意

如果您不希望将应用程序日志与(重新)构建日志及文件系统同步事件混合,也可以配合专用的 docker compose watch 命令使用 Watch。

提示

查看 dockersamples/avatars, 或 Docker 文档的本地设置 以演示 Compose watch

反馈

我们正积极寻求对该功能的反馈。请在 Compose Specification 仓库 中提供反馈或报告您发现的任何错误。

参考