Docker自动更新容器,Watchtower本地Docker部署记录

前言

在日常使用 Docker 管理多个服务容器时,一个常见的挑战是需要手动跟进每个容器的镜像更新。当部署的容器数量增多(例如 Plex、Home Assistant、Metube 等),逐一执行 docker pulldocker run 来完成更新,不仅过程繁琐,而且容易遗漏。为了解决这个问题,可以引入一个自动化工具来简化流程。Watchtower 就是为此而生的一个轻量级解决方案,它能够监控正在运行的 Docker 容器,并在其基础镜像更新时自动重新部署容器。本文旨在记录在本地环境中部署 Watchtower 的完整过程和相关注意事项。

Watchtower 简介

Watchtower 是一个专门用于自动化 Docker 容器更新的进程。它的工作流程如下:

  1. 监控所有或指定的正在运行的 Docker 容器。
  2. 定期检查这些容器所使用的镜像在镜像仓库(如 Docker Hub)中是否有新版本。
  3. 当检测到新版本时,它会自动拉取最新的镜像。
  4. 然后,它会使用与初始部署时完全相同的参数,优雅地停止并移除旧的容器,最后启动一个基于新镜像的容器。

这个工具非常适合在家庭实验室(Homelab)、个人媒体中心或开发等非生产环境中使用,能够极大地减轻维护负担。

部署方法

部署 Watchtower 的方法非常直接,可以通过 docker run 命令或 docker-compose.yml 文件来完成。

1. 使用 docker run 命令 (推荐)

这是最简单快捷的部署方式,只需一条命令即可启动 Watchtower 并让它监控所有容器。

docker run --detach \
  --name watchtower \
  --volume /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower

命令参数解析:

  • --detach-d: 使容器在后台运行。
  • --name watchtower: 为容器指定一个易于识别的名称。
  • --volume /var/run/docker.sock:/var/run/docker.sock: 这是最关键的一步。它将主机的 Docker 守护进程的 Unix socket 文件挂载到 Watchtower 容器内部。这使得 Watchtower 可以与 Docker API 通信,从而具备管理(停止、删除、创建)其他容器的权限。
  • containrrr/watchtower: 指定使用的官方镜像。

2. 使用 docker-compose.yml

如果你习惯于使用 Docker Compose 来管理服务,也可以创建一个 docker-compose.yml 文件。

version: "3.8"
services:
  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    # command: --interval 86400 # 见下文自定义说明

保存文件后,在同一目录下运行 docker-compose up -d 即可。

如何使用与自定义

1. Headless(无界面)服务

Watchtower 是一个后台服务,没有提供 Web UI 或图形化界面。它的设计理念是“部署后即忘记”(set-it-and-forget-it)。所有的配置和操作都通过启动命令的参数或 Docker Label 来定义,一旦运行起来,它就会在后台静默工作。

2. 查看运行日志

要了解 Watchtower 的工作状态,最有效的方法是查看其容器日志。

# 查看所有历史日志
docker logs watchtower

# 实时跟踪新产生的日志
docker logs -f watchtower

在日志中,你可以清晰地看到每一次检查、发现的更新、拉取镜像以及重启容器的全过程。如果没有可用更新,它也会明确地在日志中注明。

3. 自定义更新行为

  • 指定更新间隔:默认情况下,Watchtower 每24小时检查一次。可以通过在 docker run 命令末尾或 docker-compose.ymlcommand 中添加 --interval <秒数> 参数来修改,例如 --interval 3600 代表每1小时检查一次。

  • 只更新特定容器:如果你不希望 Watchtower 更新所有容器,可以在命令末尾加上你想要更新的容器的名称。

    # docker run 示例
    docker run -d \
      --name watchtower \
      -v /var/run/docker.sock:/var/run/docker.sock \
      containrrr/watchtower plex metube
    

    上述命令将只监控和更新 plexmetube 这两个容器。

  • 排除特定容器(常用):反之,如果你想更新所有容器,但要排除一两个特定容器(例如不想自动更新的数据库或 bililive-go),最佳方法是为这些容器添加 label
    docker-compose.yml 中为不想更新的服务添加 labels 块:

    services:
      bililive-go:
        image: chigusa/bililive-go
        container_name: bililive-go
        restart: unless-stopped
        labels:
          # 这行是核心,它告诉 Watchtower “不要碰我”
          - "com.centurylinklabs.watchtower.enable=false"
        # ... 其他配置 ...
    
      # watchtower 服务会读取其他容器的标签并遵守指令
      watchtower:
        image: containrrr/watchtower
        # ... 其他配置 ...
    

    添加该标签后,Watchtower 在扫描时会自动跳过这个容器。

常见问题与注意事项

问题1:如果一个镜像的作者删除了仓库(俗称“删库跑路”),会发生什么?
这是一个关系到服务稳定性的重要问题。Watchtower 的机制可以确保安全。当它尝试从一个已不存在的仓库拉取新镜像时,拉取操作会失败。Watchtower 在确认无法获取新镜像后,不会对当前正在运行的容器执行任何操作。你的服务将继续使用旧版本的镜像稳定运行,不受任何影响。你只会在 Watchtower 的日志中看到一条更新失败的记录。

问题2:容器更新后,我的配置或 .env 文件会丢失吗?
答案是:只要你遵循了 Docker 的最佳实践,配置就不会丢失。

Watchtower 的工作原理是使用与旧容器完全相同的参数重新创建一个新容器。这些参数包括了端口映射、环境变量,以及最重要的数据卷挂载 (volumes)环境变量文件 (env_file)

  • 对于普通配置文件:只要你将容器的配置文件目录(如 /config)通过 volumes 挂载到了宿主机上,数据就保存在宿主机上,新容器会重新挂载,配置不会丢失。

  • 对于 .env 文件:处理 API 密钥等敏感信息的 .env 文件同样安全,前提是正确配置。

    1. 最佳方式 (env_file): 在 docker-compose.yml 中使用 env_file: ./.env 指令。.env 文件本身保留在主机上,Docker 只是读取它并将其中的内容作为环境变量注入容器。Watchtower 重建容器时会重复这个过程,文件本身不受影响。
    2. 挂载方式 (volumes): 将 .env 文件作为单个文件挂载到容器内,例如 - ./my.env:/app/.env。文件的源头在主机上,同样是安全的。
    3. 错误方式: 永远不要docker exec 进入容器内部手动创建 .env 文件。这种方式创建的文件仅存在于容器的文件系统中,当 Watchtower 删除旧容器时,这个文件会被永久删除

总结来说,只要你的数据和配置文件(包括 .env 文件)的“源头”都通过 volumesenv_file 指令保留在宿主机上,Watchtower 的更新过程就是完全安全的。

结论

Watchtower 是一个功能强大且易于部署的工具,非常适合个人开发者和家庭实验室用户实现 Docker 容器的自动化更新。通过简单的命令行参数或 Docker label,就可以实现灵活的更新策略,例如全局更新,或排除特定服务。它遵循安全的设计原则,通过后台静默运行的方式,将手动更新的重复性劳动转变为一个可靠的自动化流程。只要正确理解其工作机制并合理配置数据卷和环境变量,就能在享受便利的同时,确保服务的稳定性和数据的持久性。