使用 Compose Watch
watch
属性会在你编辑和保存代码时自动更新和预览你正在运行的 Compose 服务。对于许多项目而言,这使得在 Compose 运行后,你就可以采用无需手动干预的开发工作流程,因为服务会在你保存工作时自动更新。
watch
遵循以下文件路径规则
- 所有路径都相对于项目目录,忽略文件模式除外
- 目录会被递归监视
- 不支持 Glob 模式
.dockerignore
中的规则适用- 使用
ignore
选项定义要忽略的附加路径(语法相同) - 常见 IDE(Vim、Emacs、JetBrains 等)的临时/备份文件会自动忽略
.git
目录会自动忽略
- 使用
你不需要为 Compose 项目中的所有服务都开启 watch
。在某些情况下,项目只有部分内容(例如 JavaScript 前端)可能适合自动更新。
Compose Watch 旨在与使用 build
属性从本地源代码构建的服务一起使用。它不跟踪依赖于由 image
属性指定的预构建镜像的服务更改。
Compose Watch 对比绑定挂载
Compose 支持在服务容器内共享主机目录。Watch 模式不会取代此功能,而是作为专门适合在容器中进行开发的伴侣存在。
更重要的是,与绑定挂载相比,watch
提供了更细粒度的控制。Watch 规则允许你忽略被监视树中的特定文件或整个目录。
例如,在 JavaScript 项目中,忽略 node_modules/
目录有两个好处
- 性能。在某些配置中,包含许多小文件的文件树可能会导致高 I/O 负载
- 多平台。如果主机操作系统或架构与容器不同,则编译后的制品无法共享
例如,在 Node.js 项目中,不建议同步 node_modules/
目录。尽管 JavaScript 是解释型语言,但 npm
包可能包含无法跨平台移植的本地代码。
配置
watch
属性定义了一个规则列表,用于控制基于本地文件更改的服务自动更新。
每条规则都需要一个 path
模式和在检测到修改时要采取的 action
。watch
有两个可能的 action,并且根据 action
的不同,可能接受或需要额外的字段。
Watch 模式可以与许多不同的语言和框架一起使用。具体的路径和规则会因项目而异,但概念保持不变。
前提条件
为了正常工作,watch
依赖于常见的可执行文件。请确保你的服务镜像包含以下二进制文件
- stat
- mkdir
- rmdir
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>
相同。
Rebuild 非常适合编译型语言,或作为需要完整镜像重建的特定文件修改(例如 package.json
)的备用方案。
同步 + 重启
如果将 action
设置为 sync+restart
,Compose 会将你的更改与服务容器同步并重启它。
当配置文件更改时,sync+restart
非常理想,你无需重建镜像,只需重启服务容器的主进程即可。例如,当你更新数据库配置或 nginx.conf
文件时,它会工作得很好。
提示
path
和 target
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
ignore
ignore
模式是相对于当前 watch
action 中定义的 path
,而不是相对于项目目录。在下面的示例 1 中,忽略路径将相对于 path
属性中指定的 ./web
目录。
示例 1
这个最小示例针对一个具有以下结构的 Node.js 应用程序
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
ignore:
- node_modules/
- action: rebuild
path: package.json
在这个示例中,运行 docker compose up --watch
时,将使用从项目根目录中的 Dockerfile
构建的镜像启动 web
服务的容器。web
服务运行 npm start
命令,该命令随后启动应用程序的开发版本,并在打包工具(Webpack, Vite, Turbopack 等)中启用热模块重载。
服务启动后,watch 模式开始监视目标目录和文件。然后,每当 web/
目录中的源文件发生更改时,Compose 会将文件同步到容器内 /src/web
下的相应位置。例如,./web/App.jsx
被复制到 /src/web/App.jsx
。
复制完成后,打包工具会更新正在运行的应用程序而无需重启。
在这种情况下,ignore
规则将应用于 myproject/web/node_modules/
,而不是 myproject/node_modules/
。
与源代码文件不同,添加新依赖不能即时完成,因此每当 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
action 来高效地开发和测试带有前端 Web 服务器和后端服务的 Node.js 应用程序。该配置确保对应用程序代码和配置文件的更改能够快速同步和应用,并且 web
服务会根据需要重启以反映这些更改。
使用 watch
- 在
compose.yaml
中为一个或多个服务添加watch
部分。 - 运行
docker compose up --watch
来构建和启动一个 Compose 项目,并启动文件 watch 模式。 - 使用你偏好的 IDE 或编辑器编辑服务源文件。
注意
如果你不想让应用程序日志与(重)构建日志和文件系统同步事件混在一起,也可以使用专用的
docker compose watch
命令。
提示
查看
dockersamples/avatars
,或Docker 文档的本地设置,以获取 Composewatch
的演示。
反馈
我们正在积极征求对此功能的反馈。请在Compose Specification 仓库中提供反馈或报告你可能发现的任何错误。