WEBKT

拒绝 K8s 重武器!5 人小团队用 Watchtower 实现 Docker 容器自动更新

23 0 0 0

对于只有几个人的初创团队或独立开发者来说,引入 Kubernetes、ArgoCD 或者复杂的 GitLab CI/CD 管道,往往是“杀鸡用牛刀”。不仅维护成本高,还容易把宝贵的开发时间浪费在修 Jenkins 脚本和配置 YAML 上。

但是,每次代码推送到镜像仓库后,还要手动 SSH 登录服务器、执行 docker pulldocker stopdocker run,这种原始的手工运维同样让人抓狂。

有没有一种方案:既能像大厂一样实现自动部署,又不需要维护任何复杂的流水线?

答案就是 Watchtower

本文将为你提供一份专为 5 人左右小团队定制的 Watchtower 极简运维指南。


什么是 Watchtower?

Watchtower 是一款开源的 Docker 容器工具。它本身也是一个容器,启动后会监控运行在同一台宿主机上的其他容器。

它的工作原理非常简单粗暴:

  1. 定期检查本地运行的容器,并比对镜像仓库(如 Docker Hub、阿里云镜像服务等)中的最新版本。
  2. 如果发现镜像有更新,它会优雅地关闭老容器。
  3. 下载新镜像,并使用最初启动该容器时完全相同的参数(环境变量、端口映射、卷挂载等)把新容器跑起来。

你不需要写任何更新脚本,它自己就能完成闭环。


快速上手:一句话启动

如果你的服务器上只跑了几个无状态的微服务,直接在终端运行以下命令:

docker run -d \
  --name watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower \
  --cleanup \
  --interval 300

参数解释:

  • -v /var/run/docker.sock:/var/run/docker.sock:这是核心。把宿主机的 Docker 守护进程挂载给 Watchtower,让它有权管理其他容器。
  • --cleanup:自动更新后,把旧镜像删掉,防止撑爆服务器硬盘。这对于小容量云服务器至关重要。
  • --interval 300:每 300 秒(5 分钟)检查一次更新。

生产环境的“懒人”进阶配置

上面的极简模式虽然爽,但在实际生产中,直接无脑更新所有容器会带来灾难。比如:

  • 你的数据库(MySQL/Redis)绝对不能跟着自动更新,万一版本跨度大导致数据损坏就崩了。
  • 业务高峰期自动重启可能会导致短暂的请求中断。

为了让 5 人团队睡个安稳觉,我们需要对配置进行微调。推荐使用 docker-compose 来管理 Watchtower。

1. 推荐的 docker-compose.yml 配置

version: '3'
services:
  watchtower:
    image: containrrr/watchtower:latest
    container_name: watchtower
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      # 只更新带有特定 label 的容器(安全第一)
      - WATCHTOWER_LABEL_ENABLE=true
      # 清理无用镜像
      - WATCHTOWER_CLEANUP=true
      # 每天凌晨 3:30 执行更新(避免工作时间中断业务)
      - WATCHTOWER_SCHEDULE=0 30 3 * * *
      # 开启通知(以钉钉/飞书/邮件为例)
      - WATCHTOWER_NOTIFICATIONS=shoutrrr
      - WATCHTOWER_NOTIFICATION_URL=generic+https://oapi.dingtalk.com/robot/send?access_token=你的钉钉机器人TOKEN
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"

2. 精准控制:谁该更新,谁不该更新

在上面的配置中,我们启用了 WATCHTOWER_LABEL_ENABLE=true。这意味着 Watchtower 默认不会碰任何容器,除非你显式地允许它。

对于你需要自动更新的业务容器(比如前端、后端 API),在它们的 docker-compose.yml 中加上一个 label:

version: '3'
services:
  my-web-app:
    image: registry.cn-hangzhou.aliyuncs.com/myteam/web-app:latest
    restart: always
    ports:
      - "8080:8080"
    labels:
      # 绿灯通行,允许 Watchtower 自动更新这个容器
      - "com.centurylinklabs.watchtower.enable=true"

  my-mysql:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: secret
    # 没有配置 label,Watchtower 会自动跳过它,保障数据绝对安全

这样一来,开发人员只需要往私有仓库推一个新版的 :latest 镜像,每天凌晨 3:30,服务器就会无缝切换到最新版本。


私有镜像仓库配置

小团队一般都会把镜像放在阿里云、腾讯云或者自建的 Harbor 中。Watchtower 需要读取这些私有仓库的凭证才能拉取镜像。

最简单的方法是将宿主机的 Docker 配置文件挂载进 Watchtower:

    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      # 挂载宿主机的 docker 登录凭证
      - /root/.docker/config.json:/config.json

只要你在宿主机上执行过一次 docker login 成功登录了你的私有仓库,Watchtower 就能直接复用这个凭证。


团队避坑指南

  1. 别用 latest 标签管理所有环境:建议开发环境用 :latest 配合 Watchtower 自动更新。生产环境依然建议使用带版本号的标签(如 :v1.2.0),通过手动修改 Compose 文件中的版本号来触发 Watchtower 更新,保留最后一层人工确认。
  2. 状态丢失问题:确保你的业务容器是无状态的。所有需要持久化的数据(如上传的文件、日志)必须通过 volumes 挂载到宿主机。否则容器重启后,数据会全部消失。
  3. 数据库迁移(Migrations):如果新版本代码包含了数据库表结构变更,自动更新可能会导致新代码与旧表结构冲突。推荐的做法是在业务代码启动脚本中加入 migration 逻辑,或者在更新前手动执行迁移。

结语

DevOps 的本质是提高交付效率,而不是堆砌高大上的工具。对于 5 人团队,省下折腾 K8s 的时间和精力去打磨产品,远比追求绝对的“高可用”来得划算。

用 Watchtower + Docker Compose 搭建这套“半自动”发布流程,通常只需要 20 分钟。配置好之后,你就可以放心地把部署工作交给代码提交,继续享受“懒人”的快乐了。

运维不加班 DockerWatchtower自动化运维

评论点评