一、项目速览

入门 · 1 分钟版

Watchtower 是一个 Docker 容器自动更新工具。它像一个不知疲倦的管家,定时检查你正在运行的容器是否有新镜像可用——如果有,就自动拉取新版本、优雅关闭旧容器、再用完全相同的参数重新启动。

它解决的核心痛点:个人开发者的服务器上跑着十来个 Docker 容器(比如 Nginx、Gitea、Jellyfin),每次镜像更新都要手动 docker pull && docker stop && docker run,时间长了必然漏掉某个容器的安全补丁。Watchtower 把这一串操作自动化了。

谁最该用:家庭实验室(homelab)玩家、NAS 用户、本地开发环境维护者、自建媒体服务器(Plex/Jellyfin)爱好者。官方 README 明确说了:不推荐用于生产环境,那是 Kubernetes 的战场。

一句话判断:如果你有 3 个以上需要手动更新的 Docker 容器,又不想上 K8s 那一套,Watchtower 就是为你准备的。

二、核心功能与架构

进阶 · 推荐细读

Watchtower 本身也是一个 Docker 容器,它的工作原理并不复杂:通过挂载宿主机的 Docker 套接字(/var/run/docker.sock)获得控制 Docker 守护进程的能力,然后按设定的时间间隔轮询镜像仓库,检查容器使用的镜像是否有更新。

核心机制:它并不是监控 Docker Hub 的 Webhook,而是主动轮询。默认每 24 小时检查一次,你也可以通过环境变量 WATCHTOWER_POLL_INTERVAL 改成任意秒数。

容器生命周期管理:发现新镜像后,Watchtower 会先向旧容器发送 SIGTERM 信号,等待默认 10 秒的优雅关闭时间(可配置),然后才强制停止并重启。这意味着你的容器如果实现了优雅关闭(比如正在处理的请求不会突然中断),更新过程对用户几乎无感。

通知系统:这是 Watchtower 的隐藏亮点。它支持 20+ 种通知渠道——邮件、Slack、Discord、Telegram、Gotify、Pushover 等等。更新成功或失败时,可以即时推送到你的手机上。

作者视角补充:我专门测过通知系统,最容易踩的坑是环境变量名大小写问题。比如 Slack 通知,正确的变量是 WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL,但很多人写成 SLACK_WEBHOOK,结果静默失败。Watchtower 不会报错,只是不发通知,排查起来很烦。

更新策略:你可以通过 --label-enable 参数实现「白名单」模式——只在容器上打了 com.centurylinklabs.watchtower.enable=true 标签的容器才会被更新。也可以排除特定容器(--ignore 参数),或者只更新指定容器(在启动命令后面跟容器名)。

三、动手实践

入门

环境准备

前提条件很简单:一台安装了 Docker 的 Linux 机器(或 macOS/Windows 的 Docker Desktop),并且你对该机器有 docker 命令的执行权限。

最小可运行示例

最基础的启动命令——让 Watchtower 监控所有容器,每 30 秒检查一次:

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower \
  --interval 30

启动后,你可以用一个「会定期更新」的测试容器来验证效果。比如运行一个 Nginx 容器,然后手动打一个新标签:

# 先跑一个 Nginx
docker run -d --name test-nginx nginx:1.25-alpine

# 查看 Watchtower 日志,看它是否发现了更新
docker logs watchtower --tail 20

如果一切正常,你会看到类似 Found new image nginx:1.25-alpineRestarting test-nginx 的日志输出。

作者视角补充:第一次测试时,建议用 --interval 30 而不是默认的 86400 秒(24 小时),否则你要等一整天才能看到效果。确认正常后再改回合理间隔(比如每小时或每天)。

带通知的配置

让 Watchtower 更新完后发消息到你的 Telegram:

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e WATCHTOWER_NOTIFICATIONS=telegram \
  -e WATCHTOWER_NOTIFICATION_TELEGRAM_BOT_TOKEN=你的BOT_TOKEN \
  -e WATCHTOWER_NOTIFICATION_TELEGRAM_CHAT_ID=你的CHAT_ID \
  containrrr/watchtower

常见踩坑

  1. Docker 套接字权限不足:如果你用 rootless Docker,套接字路径不是 /var/run/docker.sock,而是 ~/.docker/run/docker.sock。需要挂载正确的路径,或者给容器加上 --user root

  2. 容器重启后 IP 变了:Watchtower 会用相同参数重启容器,但如果你的容器依赖固定 IP(比如通过 --ip 指定),重启后 IP 可能会变。建议用 Docker 网络(--network)和容器名通信,而不是硬编码 IP。

  3. Watchtower 把自己也更新了:这是最经典的问题。如果你运行了 Watchtower,它发现了自己的新镜像,就会把自己停掉重启——导致短暂中断。解决方法:用 --label-enable 模式,给 Watchtower 容器打上 com.centurylinklabs.watchtower.enable=false 标签,或者直接用 --watchtower 参数排除自己(但某些版本不支持)。

CI 构建状态

四、进阶玩法

深入 · 老手可选

白名单模式 + 私有仓库认证

如果你只希望特定容器被更新,同时你的镜像来自私有仓库,可以这样配置:

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /home/user/.docker/config.json:/config.json \
  -e WATCHTOWER_POLL_INTERVAL=3600 \
  -e HOME_=/config.json \
  containrrr/watchtower \
  --label-enable

然后在需要被更新的容器上打标签:

docker run -d \
  --label com.centurylinklabs.watchtower.enable=true \
  --name my-app \
  my-private-registry.com/my-app:latest

单次运行模式(One-shot)

有时候你不想让 Watchtower 常驻,只想手动触发一次更新检查。可以用 --run-once 参数:

docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower \
  --run-once \
  --interval 0

这会在检查完所有容器后自动退出,适合放在 crontab 里按需执行。

Docker Compose 集成

如果你用 Docker Compose 管理服务,可以这样把 Watchtower 集成进来:

version: '3.8'

services:
  watchtower:
    image: containrrr/watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WATCHTOWER_POLL_INTERVAL=86400
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_NOTIFICATIONS=slack
      - WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL=https://hooks.slack.com/services/xxx
    command: --label-enable

  my-app:
    image: my-app:latest
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

WATCHTOWER_CLEANUP=true 会在更新后自动删除旧镜像,避免磁盘被占满。

五、判断与建议

进阶 · 推荐细读

应该选 Watchtower 的场景

  • 家庭实验室 / NAS 环境:跑着 5-20 个容器,希望保持镜像最新但不想要 K8s 的运维复杂度
  • 个人开发服务器:频繁迭代的 side project,每次 push 后希望服务器自动拉取最新版本
  • 媒体服务器:Jellyfin / Plex / Sonarr / Radarr 这类更新频繁的容器,手动更新太麻烦
  • 非关键服务:即使更新过程中有短暂中断(10-30 秒),对使用体验影响不大

不应该选 Watchtower 的场景

  • 生产环境:官方自己都说了不推荐。生产环境需要滚动更新、回滚、健康检查、蓝绿部署——这些是 K8s 的领域
  • 有状态服务:数据库(MySQL / PostgreSQL / Redis)绝对不能自动更新。一个版本升级可能破坏数据格式
  • 需要精确控制更新窗口:如果你必须在凌晨 3 点更新,且更新前要备份数据,Watchtower 的轮询机制不够精细
  • 容器数量超过 50 个:Watchtower 的轮询策略在大规模场景下效率低,且同时重启多个容器可能造成资源争抢

最终结论:Watchtower 是个人开发者的「懒人神器」,但不是运维工程师的「生产工具」。如果你的场景落在家庭实验室或非关键服务上,它能省掉你 90% 的容器更新操作;如果你在管线上服务,请直接去学 K3s 或 MicroK8s。

项目信息

项目
仓库 containrrr/watchtower
语言 Go
Star 24,654
Fork 1,140
主页 https://containrrr.dev/watchtower/

参考链接