WUD:轻松管理 Docker 容器更新

当你运行的容器越来越多,手动更新你的容器会变得越来越复杂。这时候我们就需要一个能够自动化更新容器的工具,所以在本文中我们来介绍一个能够实现这个操作的工具:WUD(What's up Docker?)。

什么是 WUD

WUD 是 What's up Docker?的缩写,当然我是揣测不到作者为啥起这么个名字,但是这并不影响它能干什么。WUD 是一个跟 WatchTower 一样的 Docker 容器自动化更新程序,其基本操作与 WatchTower 一致,都是通过 label 对容器进行识别和管理。

这两个应用之间最大的区别是 WUD 提供了一个 WebUI,来让你能够看到目前 WUD 的系统状态。但是这个 WebUI 基本真的只能用来看状态,所有的配置项和标记实际上都是与 WatchTower 相同的通过环境变量和容器标记来实现的。

部署 WUD

部署 WUD 所需的 docker-compose.yaml 内容如下:

services:
  whatsupdocker:
    container_name: whatsupdocker
    environment:
      # === 基本服务器配置 ===

      # 是否启用 WebUI (默认 true)
      # WUD_SERVER_ENABLED: false
      # 默认监控所有容器
      WUD_WATCHER_LOCAL_WATCHBYDEFAULT: false

      # === 自定义镜像源配置 ===
      # 详情参照下文“镜像源配置”章节
      # WUD_REGISTRY_CUSTOM_{{镜像源显示名}}_URL: http://localhost:5000
      # WUD_REGISTRY_CUSTOM_{{镜像源显示名}}_LOGIN: username
      # WUD_REGISTRY_CUSTOM_{{镜像源显示名}}_PASSWORD: password
      # WUD_REGISTRY_CUSTOM_{{镜像源显示名}}_AUTH: token

      # === 触发器(执行器)配置 ===
      # 详情参照下文“触发器配置”章节
      # WUD_TRIGGER_{{触发器类型}}_{{触发器名}}_{{触发器配置项}}: XXX

      # === 监控源配置 ===
      # 详情参照下文“监控源配置”章节
      # WUD_WATCHER_{{监控源显示名}}_{{配置项}}: XXX

      # === 杂项配置 ===
      # HTTP_PROXY: http://<代理连接地址>:<代理端口> # 若要使用代理,请替换成你自己的代理地址
      # HTTPS_PROXY: http://<代理连接地址>:<代理端口> # 若要使用代理,请替换成你自己的代理地址
      # NO_PROXY: 127.0.0.0/8,192.168.0.0/16,localhost
      TZ: Asia/Shanghai
    image: getwud/wud:latest
    ports:
      - 3000:3000
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/store # 数据存储

直接启动编排,如果你没有禁用 WebUI 的话,访问 http://<Server-IP>:3000 即可打开 WUD WebUI

WebUI 主页

WUD 的工作流程

当你按照上文部署完 WUD 以后,你会发现它什么都干不了,这是刻意为之的。如果你不希望自己的系统在某次意外升级后升天,那么对于这类能够自动为你更新容器的工具最好手动进行配置,只让它更新你想更新的东西。

WUD 的主要工作系统由三大基础组件构成,它们分别是镜像源(Registries)、触发器(Triggers)和监控器(Watchers)。

  • 镜像源定义了 WUD 应当从哪些位置查询镜像更新,默认包含常见的镜像源。

  • 触发器定义当 WUD 检测到某个容器镜像的更新时,WUD 可以触发哪些操作。

  • 监控器定义了 WUD 运行期间应当根据什么规则检测什么容器的更新。

所以 WUD 的工作流程是:当 WUD 启动后会索引所有已定义的监控器并为其创建定时任务,定时从镜像源查询当前监控的容器是否存在更新,若存在更新触发当前系统中符合更新规则的触发器执行诸如容器更新、发送通知等一系列动作。

镜像源配置(Registries)

镜像源定义了 WUD 应当从哪些位置查询镜像更新,默认包含以下镜像源:

  • ECR (Amazon Elastic Container Registry)

  • GCR (Google Container Registry)

  • GHCR (Github Container Registry)

  • HUB (Docker Hub)

  • Quay

当然默认均为 Anonymous Access,即匿名访问权限。默认的配置已经足够 99% 的用户使用了,但是众所周知的是,这些镜像源无一例外的都被墙了。所以在上文的部署模板中,杂项配置里我特地加入了关于代理配置相关的配置项,只需要修改对应的代理地址即可直接使用内置的镜像源。

当然,你也可以自定义配置使用国内源或私有镜像源,这便是本章节讲解的主要内容。具体来说,如果你想要在 WUD 中创建自定义镜像源,你只需要在环境变量中添加以下内容:

WUD_REGISTRY_CUSTOM_{{镜像源显示名}}_URL: http://localhost:5000
WUD_REGISTRY_CUSTOM_{{镜像源显示名}}_LOGIN: username
WUD_REGISTRY_CUSTOM_{{镜像源显示名}}_PASSWORD: password
WUD_REGISTRY_CUSTOM_{{镜像源显示名}}_AUTH: token

其中 {{镜像源显示名}} 可以自定义设定,为了兼容性最好使用纯大写字母和短横线 - 。在这 4 项设定中,除了第一项 URL 为必须设定外,其他按需设定即可。比如如果我要让 WUD 使用 1Panel 镜像源可以这样设定:

WUD_REGISTRY_CUSTOM_1PANEL_URL: https://docker.1panel.live

当然,只需要设定不同的 {{镜像源显示名}} 即可创建多个镜像源:

# 1Panel 镜像源
WUD_REGISTRY_CUSTOM_1PANEL_URL: https://docker.1panel.live
# 本地部署的镜像代理
WUD_REGISTRY_CUSTOM_HOME_URL: https://my-docker-repository
WUD_REGISTRY_CUSTOM_HOME_LOGIN: username
WUD_REGISTRY_CUSTOM_HOME_PASSWORD: password

完成设定后,在 WebUI 中打开 Registries 页面即可看到你设定的镜像源:

自定义镜像源

触发器配置(Triggers)

触发器定义了当 WUD 检测到某个容器镜像的更新时,WUD 可以触发哪些操作。即 WUD 定义中是 容器更新 *触发* 一个动作 ,所以 WUD 中将其命名为触发器,但实际上这个东西定义的是事件触发之后应该执行什么动作,大概叫做执行器会更好理解。

触发器的配置结构

触发器的配置也是写在 WUD 的环境变量中的,其基本结构为:

WUD_TRIGGER_{{触发器类型}}_{{触发器名称}}_{{触发器配置项}}: 配置项值

系统中可以有任意数量个触发器,只要他们的 {{触发器名称}} 不同即可。所有的触发器有一些通用配置项,它们是:

# 自动执行触发器,若此项为 false 则只能通过 WebUI / API 来手动执行更新操作。布尔值,默认 true,推荐 false
WUD_TRIGGER_{{触发器类型}}_{{触发器名称}}_AUTO: true
# 发现多个更新项时依次更新每个容器还是一次性更新全部的容器。可选 simple=依次升级 / batch=批量升级
WUD_TRIGGER_{{触发器类型}}_{{触发器名称}}_MODE: simple
# 执行操作时仅执行一次(不重复执行相同操作,比如升级失败时避免死循环更新)。布尔值,默认 true
WUD_TRIGGER_{{触发器类型}}_{{触发器名称}}_ONCE: true
# 容器更新阈值,可选 all, major, minor, patch,详情见下文描述
WUD_TRIGGER_{{触发器类型}}_{{触发器名称}}_THRESHOLD: all

在这些选项中,WUD_TRIGGER_{{触发器类型}}_{{触发器名称}}_THRESHOLD 的值设定较为特殊,它是根据语义化版本号进行的更新操作,WUD 也是根据语义化版本号为基准进行的更新检查。假设一个容器镜像的版本号是 2.1.1-alpha,那么在此版本号中:

2.1.1-alpha
^ ^ ^ ^
| | | |
| | | pre-release
| | patch
| minor
major

此处 WUD_TRIGGER_{{触发器类型}}_{{触发器名称}}_THRESHOLD 的设置值为 all > major > minor > patch,即当值设置为 minor 时,WUD 会监测包含 minor 和 patch 的更新,对应上文的例子中就是 2.x.x-x 的更新。

在 WUD 中可以选择执行的动作分为两大类:“容器更新”和“通知”

  • 容器更新:控制 WUD 在检测到某个容器的镜像版本存在更新时,WUD 该怎样更新该容器。

  • 通知:控制 WUD 在检测到某个容器的镜像版本存在更新时,该怎么向用户/其它系统发送通知。

容器更新操作

这是部署 WUD 的目的,所以我们优先介绍如何配置一个容器更新操作。在这一类触发器中,又有两个变种:

  • Docker:仅更新容器镜像版本,相当于在保持容器全部参数配置不变的情况下执行镜像替换。如果此容器位于某个容器编排内部,则更新该容器时对应容器编排内的容器版本并不会更新。但此更新操作不会影响容器在编排内的从属关系,更新后的容器仍受容器编排控制。

    • 优点:配置简单,不管有多少容器只需要一个触发器配置即可。

    • 缺点:只能更新容器版本,如果日后调整了容器编排文件并重新部署则新部署的容器会被还原成容器编排中指定的版本。

  • Docker Compose:更新容器镜像版本及其对应的容器编排文件内的镜像版本。

    • 优点:更新完备,不会由于意外重新部署导致容器使用的镜像被还原到旧版本。

    • 缺点:每一个要监控的容器编排文件都必须被挂载进 WUD 中,且每一个编排都需要创建一个单独的触发器配置。

你可以根据自己的需求灵活选择触发器,不同种类的触发器也可以在系统中共存,且可以通过更新策略限定某个容器更新时能使用的触发器。

Docker 容器镜像更新

只需要在环境变量中添加以下内容:

# Docker 触发器(执行器)
WUD_TRIGGER_DOCKER_{{触发器名称}}_AUTO: false    # 禁用触发器自动执行
WUD_TRIGGER_DOCKER_{{触发器名称}}_MODE: simple   # 依次更新所有需要更新的容器
WUD_TRIGGER_DOCKER_{{触发器名称}}_THRESHOLD: all # 容器更新阈值,参照上文说明
WUD_TRIGGER_DOCKER_{{触发器名称}}_PRUNE: true    # 清理旧镜像(仅清理未使用的镜像)
WUD_TRIGGER_DOCKER_{{触发器名称}}_DRYRUN: false  # 仅拉取镜像,不进行更新操作

此触发器可以被所有容器使用,所以你可以直接使用以下配置:

# Docker 触发器(执行器)
WUD_TRIGGER_DOCKER_CONTAINER_AUTO: false
WUD_TRIGGER_DOCKER_CONTAINER_MODE: simple
WUD_TRIGGER_DOCKER_CONTAINER_THRESHOLD: all
WUD_TRIGGER_DOCKER_CONTAINER_PRUNE: true
WUD_TRIGGER_DOCKER_CONTAINER_DRYRUN: false

当你设定完此触发器以后,在 WebUI Triggers 页面就可以看到了:

Docker 触发器

Docker Compose 容器镜像&编排更新

首先,在环境变量中添加以下内容(注意替换双括号文本):

# Docker Compose 触发器(执行器)
WUD_TRIGGER_DOCKERCOMPOSE_{{触发器名称}}_AUTO: false    # 禁用触发器自动执行
WUD_TRIGGER_DOCKERCOMPOSE_{{触发器名称}}_MODE: batch    # !!!此触发器仅支持批量更新模式
WUD_TRIGGER_DOCKERCOMPOSE_{{触发器名称}}_THRESHOLD: all # 容器更新阈值,参照上文说明
WUD_TRIGGER_DOCKERCOMPOSE_{{触发器名称}}_FILE: /path/to/docker-compose.yml # 容器编排文件地址
WUD_TRIGGER_DOCKERCOMPOSE_{{触发器名称}}_BACKUP: true   # 更新前先备份容器编排(旧编排将会被改为.back后缀)
WUD_TRIGGER_DOCKERCOMPOSE_{{触发器名称}}_PRUNE: true    # 清理旧镜像(仅清理未使用的镜像)
WUD_TRIGGER_DOCKERCOMPOSE_{{触发器名称}}_DRYRUN: false  # 仅拉取镜像,不进行更新操作

之后,在 WUD 容器编排的 volumes 配置中,添加:

# 如果只有一个编排文件
- /compose-name/docker-compose.yml:/external/compose-name/docker-compose.yml
# 如果你所有编排全部都在同一个文件夹下
- /composes:/external

假设你在 /opt/test/docker-compose.yml 中有一个容器编排,那么你可以这样进行设定:

# ===== 环境变量配置 =====
# Docker Compose 触发器(执行器)
WUD_TRIGGER_DOCKERCOMPOSE_COMPOSE-TEST_AUTO: false    # 禁用触发器自动执行
WUD_TRIGGER_DOCKERCOMPOSE_COMPOSE-TEST_MODE: batch    # !!!此触发器仅支持批量更新模式
WUD_TRIGGER_DOCKERCOMPOSE_COMPOSE-TEST_THRESHOLD: all # 容器更新阈值,参照上文说明
WUD_TRIGGER_DOCKERCOMPOSE_COMPOSE-TEST_FILE: /external/test/docker-compose.yml # 容器编排文件地址
WUD_TRIGGER_DOCKERCOMPOSE_COMPOSE-TEST_BACKUP: true   # 更新前先备份容器编排(旧编排将会被改为.back后缀)
WUD_TRIGGER_DOCKERCOMPOSE_COMPOSE-TEST_PRUNE: true    # 清理旧镜像(仅清理未使用的镜像)
WUD_TRIGGER_DOCKERCOMPOSE_COMPOSE-TEST_DRYRUN: false  # 仅拉取镜像,不进行更新操作

# ===== volumes 挂载 =====
- /opt/test/docker-compose.yml:/external/test/docker-compose.yml

在 WebUI Triggers 页面就可以看到效果了:

Docker Compose 触发器

通知操作

此种触发器支持的种类很多,具体的配置可以参照官方文档,这里只简单讲解 SMTP 邮件通知该如何配置。

对于 SMTP 的配置与先前触发器的添加方式基本一致,在 WUD 环境变量中添加以下内容即可:

#* SMTP 触发器
WUD_TRIGGER_SMTP_{{触发器名称}}_HOST: smtp.exmaple.com #【必填】SMTP 服务器
WUD_TRIGGER_SMTP_{{触发器名称}}_PORT: 465              #【必填】SMTP 服务器端口
WUD_TRIGGER_SMTP_{{触发器名称}}_FROM: mail@example.com #【必填】发件地址
WUD_TRIGGER_SMTP_{{触发器名称}}_TO: user@example.com   #【必填】通知接收人
WUD_TRIGGER_SMTP_{{触发器名称}}_USER: username     # SMTP 身份认证用户名
WUD_TRIGGER_SMTP_{{触发器名称}}_PASS: password     # SMTP 身份认证密码
WUD_TRIGGER_SMTP_{{触发器名称}}_TLS_ENABLED: false # 启用 TLS 加密
WUD_TRIGGER_SMTP_{{触发器名称}}_TLS_VERIFY: true   # 验证服务器 TLS 证书是否有效

在 WebUI Triggers 页面就可以看到效果了:

SMTP 触发器

监控源配置(Watchers)

完成镜像源与触发器的配置以后,就可以来配置到底要 WUD 监控哪些容器来进行更新了。

监控源由两部分构成:

  1. 添加监控源:为 WUD 配置可用于监控的 Docker Engine 连接。

  2. 配置更新策略:在目标容器处配置 WUD 应当如何处理该容器的更新。

添加监控源

在 WUD 中,当你添加一个监控源后,WUD 即有能力监控该 Docker Engine 下所有的容器(不管在不在运行)。而监控源则可以定义 WUD 该如何监控此 Docker Engine 下的容器,具体配置如下:

#* 监控源配置
WUD_WATCHER_{{监控源显示名}}_CAFILE:   # Docker TLS 连接 CA 证书
WUD_WATCHER_{{监控源显示名}}_CERTFILE: # Docker TLS 连接证书
WUD_WATCHER_{{监控源显示名}}_KEYFILE:  # Docker TLS 连接密钥
WUD_WATCHER_{{监控源显示名}}_CRON: "0 * * * *" # 更新检查间隔,CRON 表达式,默认为每小时
WUD_WATCHER_{{监控源显示名}}_HOST:      # Docker 连接地址
WUD_WATCHER_{{监控源显示名}}_PORT: 2375 # Docker 连接端口
WUD_WATCHER_{{监控源显示名}}_SOCKET: /var/run/docker.sock # Docker 连接 Socket 文件
WUD_WATCHER_{{监控源显示名}}_WATCHALL: false      # 监控所有状态下的容器(默认只监控运行状态下的容器)
WUD_WATCHER_{{监控源显示名}}_WATCHBYDEFAULT: true # 默认监控此监控源下的所有容器
WUD_WATCHER_{{监控源显示名}}_WATCHEVENTS: true    # 监听此监控源容器状态事件(比如当容器从停止变为运行时检测此容器更新)

在这份配置中,Docker Engine 的连接方式二选一即可,若你选择 TLS / HTTP 连接,此时必须设置 HOSTPORT(TLS 额外设置 CERTFILEKEYFILE);若你选择 Socket 连接,则只需要设定 SOCKET 即可。你可以添加任意数量个监控源,只需要保证其 {{监控源显示名}} 不同即可。

默认情况下,WUD 会主动监控所有监控源下所有正在运行的容器更新,此时如果你的触发器中存在一个 WUD_TRIGGER_DOCKER_{{触发器名称}}_AUTOtrue 的触发器时,当检查到任意一个容器更新时会执行该触发器。所以推荐当你添加监控源时,将 WUD_WATCHER_{{监控源显示名}}_WATCHBYDEFAULT 设为 false 来禁止 WUD 自动监控此监控源下所有容器,在下文通过配置更新策略来控制 WUD。

如果你什么都不设定且在 WUD 的 volumes 中挂载 /var/run/docker.sock 文件时,会自动创建的一个名称为 local的监控源。所以在最开始的 WUD 容器编排中,有一行环境变量是:WUD_WATCHER_LOCAL_WATCHBYDEFAULT: false,即默认不监控此监控源内的容器。如果你需要对本地监控源做其他调整,只需要同样的添加配置项并将 {{监控源显示名}} 设定为 local 即可。

配置更新策略

注意!此处的配置是在你要检查更新的容器/容器编排处进行配置

以下例子中包含了一个带有更新配置的数据库容器编排示例文件:

services:
  test-postgres:
    container_name: test-postgres
    environment:
      - TZ=Asia/Shanghai
      - POSTGRES_USER=aaa
      - POSTGRES_PASSWORD=bbb
    image: postgres:16.3-alpine
    # WUD 容器更新策略配置
    labels:
      - wud.watch=true
      - wud.display.name=PostgreSQL
      - wud.tag.include=^16\.\d+-alpine$$
    ports:
      - 5432:5432
    restart: unless-stopped

警告!此处示例仅限示例用途,请勿将此编排用于生产环境数据库配置

在上述文件中的 labels 定义了一系列将会被 WUD 进行检索和识别的标签,上面的策略配置的意思是:

  • wud.watch=true:为此容器启用检查更新。

  • wud.display.name=PostgreSQL:此更新规则在 WUD WebUI 中的显示名称。

  • wud.tag.include=^16\.\d+-alpine$$:仅当新版本的版本号符合此正则表达式时才提示更新,此处末尾的 $$ 并不是错误,而是 yaml 的语法规定如此,为了读者方便,下文均使用 $$ 代替 $

此时,该配置文件在 WUD WebUI 中显示如下:

更新规则设置效果

此时由于我的 Docker Compose 中设定的版本是 16.3-alpine,且对版本号设定了只有符合 ^16\.\d+-alpine$$ 这个正则表达式限制,所以即使 PostgreSQL 此时已有 18.x 版本,在 WUD 中依然只会检测到 16.9-alpine 的更新。

当然可用的标签不止上面提到的那三种,完整的可用标签列表如下:

标签

允许值

描述

默认值

wud.display.icon

String

设定该监控项在 WebUI 中显示的图标,参照官方文档

mdi:docker

wud.display.name

String

设定该监控项在 WebUI 中的显示名

容器名

wud.link.template

String

通过模板设定一个可访问的更新详情 URL,见下文

wud.tag.exclude

JavaScript 正则表达式

*排除符合此正则表达式的更新

wud.tag.include

JavaScript 正则表达式

*仅允许符合此正则表达式的更新

wud.tag.transform

$正则 => $正则匹配组

镜像 Tag 转换规则,见下文

wud.trigger.exclude

$触发器1_ID,$触发器2_ID:$阈值

**在此监控项检查到更新时,不执行设定的触发器

wud.trigger.include

$触发器1_ID,$触发器2_ID:$阈值

**在此监控项检查到更新时,仅执行设定的触发器

wud.watch.digest

Boolean

检查校验和更新,见下文

false

wud.watch

Boolean

为此容器启用检查更新

与此监控源的 WATCHBYDEFAULT 设定相同

接下来解释上文所列出的部分标签:

wud.link.template

此项可以用于设定在 WUD WebUI 中显示一个可访问的更新日志链接,此项为 JavaScript 模板字符串,可以使用的模板变量有:

  • ${original}:原始 Tag 名

  • ${transformed}:经过 wud.tag.transform 转换过的 Tag 名

  • ${major}:当 tag 是一个语义化版本号时对应的 major 版本号

  • ${minor}:当 tag 是一个语义化版本号时对应的 minor 版本号

  • ${patch}:当 tag 是一个语义化版本号时对应的 patch 版本号

  • ${prerelease}:当 tag 是一个语义化版本号时对应的 pre-release 版本号

以本章节开始的 PostgreSQL 举例,可以设定以下更新日志链接:

- wud.link.template=https://www.postgresql.org/docs/release/$${major}.$${minor}/

此时在 WebUI 中会显示一个更新日志链接:

更新日志链接效果

wud.tag.transform

在上文中提到了一个 Tag 转换,这是因为 WUD 检测镜像更新有两种方式,默认所使用的是检测镜像 Tag。这就要求镜像 Tag 必须是符合语义化版本号规则的形式,那么对于某些“不守规矩”的镜像 Tag,比如 searx/searx:1.0.0-269-7b368146

此时它的版本号是 $major.$minor.$patch-$prerelease-$digest,末尾多了个校验和,那么我们就可以通过此表填提供一个正则表达式匹配组来删除多余的字符,我们可以这样设置:

- wud.tag.transform=^(\d+\.\d+\.\d+-\d+)-.*$$ => $$1

这里所应用的规则是来源于 JavaScript,我们可以在浏览器中运行以下代码:

ver='1.0.0-269-7b368146'
// 匹配版本号
patt=/^\d+\.\d+\.\d+-\d+-.*$/
patt.exec(ver)
// 匹配分组后的版本号
patt=/^(\d+\.\d+\.\d+-\d+)-.*$/
patt.exec(ver)

此处的两次运行会拿到两个结果:

正则表达式匹配结果 1

正则表达式匹配结果 2

可以看到,分组后的正则表达式,在匹配版本号时多了一个匹配组,而这个匹配组正是我们想要的,而它此时位于数组下标为 1 的位置。这就是为何在 ^(\d+\.\d+\.\d+-\d+)-.*$$ => $$1 中,末尾的选项为 $$1 而不是 $$0 的原因。

wud.watch.digest

上文提到 WUD 有两种检测镜像更新的方式,wud.watch.digest 就是第二种方式。

绝大多数容器都会提供 latest 这个特殊的标签,它一般指向当前应用最新版本的容器镜像。有些应用例如 PostgreSQL,还额外提供了大版本号标签比如 postgres:16,这个标签永远指向 PostgreSQL v16 的最新版本镜像。

此时就可以使用 wud.watch.digest 标签,它会让 WUD 检测校验和更新,即你在 DockerHub 中,看到的这一块内容:

什么是 digest

每一个镜像的校验和都是不同的,通过设置此选项 WUD 可以检测到当前标签下你正在运行的容器镜像校验和是不是与最新的镜像校验和不同,当发现不同时就会在 WebUI 中提示你更新(或者根据触发器自动更新)。对于许多小应用程序使用 latest 标签外加此项设置可以节省大量配置时间。

wud.tag.include / wud.tag.exclude

提供一个 JavaScript 正则表达式,仅当在版本号列表中检测到符合此正则表达式的更新版本号后再进行更新。也可以通过 exclude 配置排除某些版本号以外的更新,两项设定一个即可。

wud.trigger.include / wud.trigger.exclude

提供一个由 , 分隔的 触发器ID:更新阈值 列表,来设定对于此监控项要使用/不使用哪些触发器。其中触发器 ID 可以在 WebUI 的 Triggers 页面中看到,将 / 替换为 . 即可,比如以下示例:

- wud.trigger.include=smtp.mail,docker.container:minor,dockercompose.compose-test

末尾

WatchTower 似乎有一段时间不更新了,在寻找替代品的过程中发现了 WUD,实际使用也确实没觉得很复杂,但是没想到这类工具写出来居然这么复杂......看来 Docker 也是会者不难难者不会的一种存在吧,希望这个文章能解决一部分人的需求,那也算是有价值了。


WUD:轻松管理 Docker 容器更新
https://blog.tihus.com/archives/f61f97c5-40a1-469d-b5c5-e0eebe788403
作者
Yuki
发布于
2025年05月11日
许可协议