- 运维
- DevOps
- 云原生
- 容器运行时
【免费下载链接】watchtower
A process for automating Docker container base image updates.
Watchtower 默认会监控 Docker 主机上所有容器并自动更新其镜像。本文以 docs/container-selection.md 为主线,系统讲解如何通过com.centurylinklabs.watchtower.enable与com.centurylinklabs.watchtower.monitor-only两个标签实现「完全排除」与「仅监控不更新」两种容器选择策略,并结合仓库源码说明其底层过滤与判定原理。读完本文,你将掌握 Dockerfile、docker run、docker-compose 三种场景下的标签写法,以及--label-enable、--monitor-only、--label-take-precedence等参数与标签组合后的精确行为。
背景:默认全量监控与两种定制需求
默认情况下,Watchtower 会观察所有容器:只要有新镜像可用,就会执行拉取、停旧容器、重建新容器的完整更新流程。但在真实生产环境中,你通常只希望其中一部分容器被自动更新,因此需要两种定制手段:
- 完全排除(Full Exclude):让某些容器彻底从 Watchtower 的监控范围内消失,既不检查更新、也不发送通知、更不触发任何生命周期钩子。
- 仅监控(Monitor Only):容器仍然被检查更新、发送通知,并执行 pre-check / post-check 生命周期钩子,但不会执行更新动作——适合灰度观察、变更审计或「先提醒后人工升级」的场景。
这两种能力都通过容器上的Label(标签)表达,而不是通过修改 Watchtower 自身配置,因此可以在不改动 Watchtower 部署的前提下,由各业务容器自主声明自己的更新策略。
完全排除:将 enable 标签置为 false
如果你需要排除某些容器,请在被排除的容器上(而不是 Watchtower 容器上)设置com.centurylinklabs.watchtower.enable标签为false。Watchtower 在扫描时会读取每个容器的元数据并据此过滤。
三种常见的设置方式如下。
方式一:Dockerfile 中声明
LABEL com.centurylinklabs.watchtower.enable="false"适用于镜像构建阶段就确定「该镜像产出的容器一律不参与自动更新」的场景。
方式二:docker run 命令行
docker run -d --label=com.centurylinklabs.watchtower.enable=false someimage适用于临时启动、按实例粒度隔离的场景。
方式三:docker-compose
version: "3" services: someimage: container_name: someimage labels: - "com.centurylinklabs.watchtower.enable=false"适用于以 compose 文件作为基础设施即代码(IaC)的部署方式。
注意:
version: "3"是原文档示例中的写法;若你使用的 Compose 规范较新,可省略该键。标签的键名com.centurylinklabs.watchtower.enable是硬编码的约定键,在源码 pkg/container/metadata.go 中以常量enableLabel定义,必须原样书写。
反向白名单:启用 --label-enable 只监控带标签的容器
如果默认「全监控」粒度太粗,你还可以反转语义:让 Watchtower 只监控显式打了 enable 标签且值为true的容器。方法是启动 Watchtower 时传入--label-enable参数,或设置环境变量WATCHTOWER_LABEL_ENABLE,然后在希望被监控的容器上设置值为true的 enable 标签。
该参数在源码 internal/flags/flags.go 中注册,短参数为-e:
Argument: --label-enable, -e Environment Variable: WATCHTOWER_LABEL_ENABLE Type: Boolean Default: false开启后,被监控容器上的标签写法与上文对称:
=== "dockerfile"
```docker LABEL com.centurylinklabs.watchtower.enable="true" ```=== "docker run"
```bash docker run -d --label=com.centurylinklabs.watchtower.enable=true someimage ```=== "docker-compose"
```yaml version: "3" services: someimage: container_name: someimage labels: - "com.centurylinklabs.watchtower.enable=true" ```需要说明的是,--label-enable与「容器上 enable=false 排除」是两种不同的过滤机制:前者要求必须存在enable 标签且为 true(白名单),后者则是对已存在的 enable=false 标签做否定排除。二者可以同时参与同一轮过滤,具体组合语义见下文「过滤是 AND 逻辑」。
源码视角:标签过滤到底如何工作
理解过滤逻辑,需要同时看两个层面:标签如何被读取与过滤链如何串联。
标签读取与解析
容器标签的读取与布尔解析位于 pkg/container/container.go 的Enabled()方法:
// Enabled returns the value of the container enabled label and if the label // was set. func (c Container) Enabled() (bool, bool) { rawBool, ok := c.getLabelValue(enableLabel) if !ok { return false, false } parsedBool, err := strconv.ParseBool(rawBool) if err != nil { return false, false } return parsedBool, true }它返回两个值:标签的布尔值,以及标签是否被设置。注意两点实现细节:
- 标签值使用
strconv.ParseBool解析,因此除true/false外,1/0、t/f、T/F等 Go 标准库认可的写法也能被解析; - 若标签未设置或值无法解析,一律返回
(false, false),不会报错中断扫描。
过滤链的串联方式
过滤链由 pkg/filters/filters.go 的BuildFilter构建,它在 cmd/root.go 的Run中被调用:
filter, filterDesc := filters.BuildFilter(names, disableContainers, enableLabel, scope)BuildFilter依次叠加多个「基础过滤器」(每个过滤器接收上一个过滤器作为baseFilter):
FilterByNames(names, filter)——按容器名匹配(--name参数);FilterByDisableNames(disableNames, filter)——按--disable-containers排除指定名称;FilterByEnableLabel(filter)——仅当启用--label-enable时叠加,要求容器显式存在enable 标签;FilterByScope(scope, filter)——按--scope限定监控范围;FilterByDisabledLabel(filter)——始终叠加,排除 enable 标签被显式置为 false 的容器。
其中步骤 3 的实现(pkg/filters/filters.go)验证了「必须显式设置标签」的语义:
func FilterByEnableLabel(baseFilter t.Filter) t.Filter { return func(c t.FilterableContainer) bool { _, ok := c.Enabled() if !ok { return false } return baseFilter(c) } }而步骤 5(pkg/filters/filters.go)则专门拦截 enable=false 的容器:
func FilterByDisabledLabel(baseFilter t.Filter) t.Filter { return func(c t.FilterableContainer) bool { enabledLabel, ok := c.Enabled() if ok && !enabledLabel { // If the label has been set and it demands a disable return false } return baseFilter(c) } }过滤是 AND 逻辑:所有条件必须同时满足
BuildFilter通过层层嵌套把各过滤器组合成一个复合过滤器,而嵌套的本质是AND(与)逻辑:一个容器只有通过所有层的检查才会被监控。原文档给出的两个例子精确描述了这一行为:
- 例一:容器名命中
--name监控名单(名单非空),但其 enable 标签为false→ 该容器不会被监控(被步骤 5 拦截)。 - 例二:容器已设置
enable=true且--label-enable开启,但容器名不在--name名单中(名单非空)→ 同样不会被监控(被步骤 1 拦截)。
换言之,--name、--disable-containers、enable 标签、scope 是并列的筛选维度,各维度条件全部命中才会进入监控名单。这也是原文档「A container is monitored if all criteria are met」一句的源码级含义。
补充维度:--disable-containers 与 scope
原文档还提到了与容器选择相关的两个补充参数:
--disable-containers, -x/WATCHTOWER_DISABLE_CONTAINERS(默认空):按名称排除容器,适用于「不方便改标签」的场景。其实现位于FilterByDisableNames(pkg/filters/filters.go),支持逗号或空格分隔的列表。该参数优先级很高——即便容器 enable 标签为 true,只要名字在黑名单中就会被排除。- 监控范围(scope):如果希望建立「多个独立监控圈」,需要运行多个 Watchtower 实例,并为每个实例指定
--scope参数,详见 running-multiple-instances.md。
完整参数定义可参考 docs/arguments.md 中的--label-enable、--disable-containers等小节。
仅监控:将 monitor-only 标签置为 true
单个容器可以被标记为「只监控、不更新」。做法是在该容器上设置com.centurylinklabs.watchtower.monitor-only标签为true:
LABEL com.centurylinklabs.watchtower.monitor-only="true"或通过docker run命令行指定:
docker run -d --label=com.centurylinklabs.watchtower.monitor-only=true someimage当标签被设置后,Watchtower 会把这个容器当作全局设置了WATCHTOWER_MONITOR_ONLY一样处理,但影响范围仅限于该容器——同一主机上其他未设置该标签的容器依然会被正常更新。
全局版:--monitor-only / WATCHTOWER_MONITOR_ONLY
全局的「只监控」开关在 internal/flags/flags.go 注册,短参数为-m:
Argument: --monitor-only, -m Environment Variable: WATCHTOWER_MONITOR_ONLY Type: Boolean Default: false需要特别指出的是,容器级标签与全局参数之间存在**默认「参数优先」**的关系,具体行为见下一节。
源码视角:monitor-only 的判定逻辑
容器级判定位于 pkg/container/container.go:
// IsMonitorOnly returns whether the container should only be monitored based on values of // the monitor-only label, the monitor-only argument and the label-take-precedence argument. func (c Container) IsMonitorOnly(params wt.UpdateParams) bool { return c.getContainerOrGlobalBool(params.MonitorOnly, monitorOnlyLabel, params.LabelPrecedence) } func (c Container) getContainerOrGlobalBool(globalVal bool, label string, contPrecedence bool) bool { if contVal, err := c.getBoolLabelValue(label); err != nil { ... return globalVal } else { if contPrecedence { return contVal } else { return contVal || globalVal } } }其判定规则可以归纳为:
| 容器 monitor-only 标签 | 全局--monitor-only | --label-take-precedence | 最终行为 |
|---|---|---|---|
| 未设置 | 任意 | 任意 | 使用全局值 |
| 已设置(如 true) | false | 否 | true \|\| false = true,仅监控 |
| 已设置(如 false) | true | 否 | false \|\| true = true,参数优先,仍然仅监控 |
| 已设置 | 任意 | 是 | 标签优先,完全由标签决定 |
也就是说,默认情况下参数会覆盖标签(contVal || globalVal是 OR 逻辑,全局为 true 即可使容器进入仅监控状态);只有显式开启--label-take-precedence(对应环境变量WATCHTOWER_LABEL_TAKE_PRECEDENCE,定义见 internal/flags/flags.go)后,标签才拥有最终决定权。
更新流程中的实际拦截点
「仅监控」在更新流程中的拦截点位于 internal/actions/update.go:
stale, newestImage, err := client.IsContainerStale(targetContainer, params) shouldUpdate := stale && !params.NoRestart && !targetContainer.IsMonitorOnly(params)IsMonitorOnly返回 true 时shouldUpdate为 false,容器会进入AddScanned扫描结果(internal/actions/update.go),但不会触发停止与重建。同一份逻辑在 internal/actions/update_test.go 中也有大量测试覆盖,例如验证LabelPrecedence: true且标签为monitor-only=false时容器仍会被更新(TriedToRemoveImageCount为 1),而标签为monitor-only=true时则不会被更新。
此外,cmd/root.go 还给出了一条实用提示:若同时启用WATCHTOWER_MONITOR_ONLY与WATCHTOWER_NO_PULL,可能导致 Watchtower「既不拉取也不更新」,实际不会产生任何动作——如果这是有意为之可以忽略该警告。
组合使用的决策建议
- 默认全量更新:什么标签都不打,最省心,适合开发/测试环境。
- 个别容器跳过更新:在对应容器上打
enable=false(完全排除),或打monitor-only=true(保留通知与钩子,见 docs/lifecycle-hooks.md)。 - 只更新白名单:Watchtower 加
--label-enable,并对目标容器打enable=true;未打标签的容器一律不监控。 - 按名称排除:不便改标签时使用
--disable-containers。 - 多套监控圈:运行多个实例并各自配置
--scope(详见 docs/running-multiple-instances.md)。 - 参数与标签冲突:默认参数优先;需要标签覆盖参数时开启
--label-take-precedence。
小结
Watchtower 的容器选择能力完全围绕两个核心标签展开:com.centurylinklabs.watchtower.enable控制容器是否进入监控范围(配合--label-enable可反转成白名单模式),com.centurylinklabs.watchtower.monitor-only控制容器是否只监控不更新。底层上,pkg/filters/filters.go 以 AND 逻辑串联名称、禁用名单、enable 标签与 scope 多级过滤;pkg/container/container.go 则依据标签、全局参数与--label-take-precedence三者的组合判定每个容器的最终动作。理解这两层机制,你就能在任何规模的 Docker 部署中精确、安全地划定自动更新的边界。
- 运维
- DevOps
- 云原生
- 容器运行时
【免费下载链接】watchtower
A process for automating Docker container base image updates.
相关推荐
Watchtower容器监控终极指南:如何精准控制更新范围
Watchtower容器监控终极指南:如何精准控制更新范围 Watchtower是一个强大的Docker容器自动更新工具,能够监控并更新运行中的容器镜像。默认情
运维DevOps云原生容器运行时Free Claude Code本地web_search/web_fetch工具揭秘:不花供应商钱的联网搜索
Free Claude Code本地web_search/web_fetch工具揭秘:不花供应商钱的联网搜索 ! Free Claude Code 本地网关管理
LLM 网关大模型后端AI 应用Watchtower 自我更新机制完全指南:让 Docker 容器监控器自动升级自身镜像
Watchtower 自我更新机制完全指南:让 Docker 容器监控器自动升级自身镜像 Watchtower 是一个自动化更新运行中 Docker 容器基础镜
运维DevOps云原生容器运行时
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考