更新

介绍自托管实例如何获知 Warmbly 新版本、管理面板中的更新提示代表什么,以及“更新并重启”如何拉取版本、重新构建并重启服务栈。

自托管 Warmbly 会自行检查新版本,并在管理面板显示。如果更新器与服务栈一起运行,点击一个按钮即可应用更新:获取新版本,重新创建发生变化的服务,后端恢复响应后面板重新连接。正在进行的工作不会丢失:发送和同步在重启期间暂停,之后从数据库继续。

“获取”的方式取决于实例如何安装,更新器为每种方式提供模式:

模式适用安装更新内容
image通过 install.sh 安装在 .env 固定新标签,执行 docker compose pull 并重建容器,不进行构建
composeGit 克隆执行 git pull、docker compose build,然后重建容器
command其他方式执行 git pull,再运行你自己的构建和重启脚本

更新提示

管理面板 :5174 侧边栏底部,在环境标签旁显示版本标记。它读取正在运行的后端构建身份,因此显示的是实际部署版本,不是检出目录声称的版本。

标记含义
v1.4.0,灰色已是最新。点击查看详情和手动检查
Update to v1.5.0,高亮并闪动配置渠道中已有更新发布
Update available,高亮并闪动检出目录落后于其分支,适用于跟随 main 的安装
Updating,蓝色并旋转更新任务正在运行;从任何选项卡都可通过标记跟踪
Restarting,蓝色并旋转更新后后端正在重新启动

相同信息也显示在实例 > 设置与健康状态顶部;有更新时还会出现发现项 update_available,严重级别为信息,因此只列发现的页面也会提示。

在控制台中

自托管工作区的每个成员都能在控制台顶部、套餐徽章旁看到相同版本标记:当前版本为灰色;发现新发布后,显示琥珀色“Update to vX.Y.Z”,并带闪动圆点。这样无需询问服务器运行什么版本,无权更新的人也知道有更新待处理。

能否操作取决于平台管理权限,而不是工作区角色:

  • 成员只看到徽章,提示框说明版本,并提示联系平台管理员。
  • 当前会话没有第二因素的平台管理员看到相同徽章;点击会说明管理访问需要双因素身份验证,并链接到“设置 > 安全”。在那里启用 2FA 或添加通行密钥,再重新登录;管理面板也受同一规则限制。
  • 平台管理员点击后打开更新对话框,其中有当前和可用版本、发布说明、检出目录与更新器状态、“立即检查”按钮,以及更新并重启。点击后先进入确认页面,明确说明拉取、重建、重启、发送暂停后恢复、应用迁移及选项卡重新连接,然后才执行。

更新期间,对话框显示进度条、突出当前步骤的步骤列表,以及可展开的日志。后端因重启暂时不可用时,对话框显示正在重新连接,并持续轮询;顶部版本标记变成旋转图标,因此关闭对话框仍能看到任务,刷新页面也能重新接上。新后端响应后,对话框显示结果,短暂倒计时后重新加载控制台;如果对话框已关闭,则用提示通知新版本,并刷新所有列表。

控制台通过 GET /auth/instance 获取版本,任何成员均可读取;其余信息使用下方管理端点,仅平台管理员可访问,权限规则与管理面板相同。

如何判断版本较新

有两个信号,任一出现都会点亮版本标记:

  • 发布。 将 RELEASES_GITHUB_REPO 在 UPDATE_CHANNEL 上的最新发布,与运行构建版本比较。stable 只看稳定版,dev 包含预发布。标记为 v1.4.0-3-gabc1234 的构建表示比 v1.4.0 标签多三个提交,会被视为新于 v1.4.0、旧于 v1.4.1,因此从 main 构建的实例不会被反复提醒安装已包含的发布。
  • 提交。 更新器运行时,按 UPDATER_FETCH_INTERVAL 获取远程内容,并报告检出目录落后分支多少提交。对于跟随分支的安装,落后任何数量都算更新。

没有版本信息的构建,例如未传构建参数的镜像,报告为 dev,无法与发布比较,只能使用提交差距。

版本来自二进制本身:Dockerfile 和 make up 会写入标签、提交和构建时间,使用 internal/version;CI 对公开镜像也如此,warmblyctl status 将它打印在第一行。

升级到此版本之后的版本前

新增了两项启动要求。不满足时,拉取后实例会陷入重启循环,而不是带警告启动。点击更新前应先检查两者。

  • AUTH_SECRET 至少需要 32 个字符。 它签署每个会话令牌,较短密钥可能从实例签发的任意令牌中被离线恢复。实时服务对同一个值 JWT_SECRET 应用相同下限。可以用 make gen-key 生成,或使用任意至少 32 字符的随机字符串,并写入安装的 .env。更改它会让所有人退出登录,这是预期效果,也正适合在更新时处理。
  • 管理员需要双因素身份验证。 所有管理路由都会拒绝未提供第二因素的会话。应在更新之前,至少让一位管理员在控制台的设置 > 安全中登记,否则管理面板无法访问,直到有人完成。控制台本身不受影响,因此更新后仍能登记,只是在那个时刻才发现不够方便。

用以下命令检查第一项:

awk -F= '/^AUTH_SECRET=/{print length($2)" characters"}' /opt/warmbly/.env

更新并重启

更新器可访问且存在更新时,按钮才会出现。它需要管理员权限 manage_settings,每次点击都会生成审计行,操作为 upgrade,对象为 instance。

通过 install.sh 安装、使用镜像模式时:

  1. 固定发布。 将所选标签写入 WARMBLY_TAG,保存在安装的 .env 中,让拉取、重建和以后手动执行的每次 docker compose up 都解析到相同镜像。拉取失败会恢复旧标签,避免 .env 留在不存在的镜像版本。
  2. 拉取镜像。 执行 docker compose pull。
  3. 重启。 对除更新器自身外的所有服务执行 docker compose up -d --no-build。
  4. 清理。 执行 docker image prune -f,除非设置了 UPDATER_PRUNE=false。
  5. 等待后端。 更新器轮询 /health,直到响应,最多等待六分钟。

Git 检出使用 Compose 模式时:

  1. 获取。 在检出目录执行 git fetch --tags --prune。
  2. 拉取。 位于分支时,对远程分支执行快进合并;固定在标签时,检出最新发布。有本地修改的目录会被拒绝,不会强行合并;请提交或暂存修改,或设置 UPDATER_ALLOW_DIRTY=true。
  3. 构建。 对每个服务执行 docker compose build,并写入版本信息。
  4. 重启。 对检出目录定义的全部服务,加上所有正在运行的服务,执行 docker compose up -d --no-build,排除更新器自身。Compose 只重建镜像或配置变化的容器,因此 Postgres、Redis 和 NATS 保持运行,后端启动时应用迁移。
  5. 清理。 执行 docker image prune -f,除非设置了 UPDATER_PRUNE=false。
  6. 等待后端。 更新器轮询 /health,最多六分钟,并将任务标为成功或失败。

如果更新器自己的镜像变化,它会在结果已写入磁盘后最后重建自己,让新更新器能够报告已完成任务。

对话框实时显示日志。关闭后,版本标记继续跟踪;重新加载页面也会重新接上任务。后端以新构建响应时,提示会说明当前版本,并刷新全部列表。

迁移只向前应用,因此为保证现有数据安全,更新不需要通过回滚来处理。仍请阅读备份:更新前的备份通常会让你庆幸提前准备。

更新器持有 Docker socket

更新器挂载 /var/run/docker.sock,这相当于主机 root 权限。因此在克隆安装中,它位于 updater Compose 配置组后;在所有安装中,它都只接受后端持有的持有者令牌,只在 Compose 网络响应,不公开端口。后端通过管理员权限控制按钮并记录审计。如果不希望主机授予这些信任,请关闭该配置组,手动更新。

启用更新程序

通过 install.sh 安装的实例

已经配置完成。安装器会把镜像模式更新器写入生成的 Compose 文件,指向安装目录,并生成独立 UPDATER_TOKEN,后端也从 .env 读取它。无需额外设置。

如果要手动更新,在安装目录执行:

docker compose -p warmbly pull && docker compose -p warmbly up -d

如果完全不想显示按钮,删除 updater 服务,即从 docker-compose.yml 移除它,并将 UPDATER_URL=none 写入 .env。

克隆仓库后使用 Docker Compose

make up 会带 updater 配置组启动服务栈,因此标准安装已经有按钮。如果直接执行 docker compose up,请在 .env 添加:

COMPOSE_PROFILES=updater

服务会按主机上的原路径挂载检出目录,由 WARMBLY_REPO_DIR 指定,默认 $PWD,使 Compose 文件的相对路径在容器内以相同方式解析;并将后端的 INTERNAL_API_TOKEN 共享为 UPDATER_TOKEN。无需其他配置。

Git 以 root 写入的文件,会在每次拉取后归还检出目录所有者,因此你在主机上的 git pull 仍可正常工作。

手动更新可使用 make upgrade,即快进拉取后运行 make up。完全隐藏按钮时,用 make up UPDATER=false 启动,并将 UPDATER_URL=none 写入 .env;面板之后只报告信息。

不使用 Docker

在裸机安装中,更新器是一个 systemd 单元,拉取后运行 scripts/upgrade-bare-metal.sh。脚本以检出目录所有者身份构建本机运行的所有产物,再交给唯一的特权安装器 warmbly-install-release,由它复制产物到 /opt/warmbly,保留各前端 config.js,先重启后端,待其响应后再启动其他服务。

cd /opt/warmbly/src
go build -o out/updater ./cmd/updater && sudo install -m 0755 out/updater /opt/warmbly/bin/
sudo install -o root -g root -m 0755 deploy/systemd/warmbly-install-release.sh /usr/local/sbin/warmbly-install-release
sudo install -m 0644 deploy/systemd/warmbly-updater.service /etc/systemd/system/
printf 'UPDATER_TOKEN=%s\n' "$(grep ^INTERNAL_API_TOKEN= /etc/warmbly/warmbly.env | cut -d= -f2-)" | sudo tee /etc/warmbly/updater.env >/dev/null
sudo chmod 0600 /etc/warmbly/updater.env
sudo systemctl daemon-reload && sudo systemctl enable --now warmbly-updater

单元以检出目录所有者身份运行,随附值为 deploy,请按需修改。唯一需要 root 的步骤是安装器,因此该用户只需一行精确的 sudoers 规则,不需要更大权限:

echo "deploy ALL=(root) NOPASSWD: /usr/local/sbin/warmbly-install-release" | sudo tee /etc/sudoers.d/warmbly-upgrade >/dev/null
sudo chmod 0440 /etc/sudoers.d/warmbly-upgrade

安装器归 root 所有,普通用户不可写,不接受参数,只读取检出目录下的固定路径,并拒绝其中的符号链接,因此拥有检出目录不等于拥有主机。它安装的二进制始终以无特权 warmbly 用户运行。

然后在 warmbly.env 中让后端指向更新器,并重启后端:

UPDATER_URL=http://127.0.0.1:8095

也可以手动运行相同脚本:scripts/upgrade-bare-metal.sh --pull。

配置

后端:

变量作用默认值
UPDATE_CHECK_ENABLED轮询 GitHub Releases,并在面板显示新版本true
UPDATE_CHECK_INTERVAL发布检查频率,最短 5m30m
UPDATE_CHANNELstable 跟随稳定发布,dev 也提供预发布stable
RELEASES_GITHUB_REPO将其发布视为 Warmbly 版本的 owner/repo;分支实例可指向自己的分支warmbly/warmbly
RELEASES_GITHUB_TOKEN可选,仅用于提高 GitHub API 速率额度未设置
UPDATER_URL更新器地址;未设置或为 none 时,面板只报告信息Compose 下为 http://updater:8095
UPDATER_TOKEN提交给更新器的持有者令牌。应使用独立值;一条命令安装器会生成INTERNAL_API_TOKEN

更新器:

变量作用默认值
UPDATER_TOKEN接受的令牌,回退到 INTERNAL_API_TOKEN;没有令牌时拒绝启动未设置
UPDATER_MODEimage 固定发布标签并拉取;compose 重建检出目录;command 运行 UPDATER_COMMANDcompose
UPDATER_COMMANDcommand 模式中的构建和重启命令未设置
UPDATER_REPO_DIR检出目录;镜像模式下为保存 Compose 文件和 .env 的安装目录工作目录
UPDATER_REMOTE获取和拉取使用的 Git 远程origin
UPDATER_COMPOSE_PROJECT启动服务栈时使用的 -p 值warmbly
UPDATER_COMPOSE_PROFILES每次 Compose 调用附加的配置组,使更新器自身镜像也能重建updater
UPDATER_BACKEND_HEALTH_URL重启后持续轮询直到响应http://backend:8080/health
UPDATER_FETCH_INTERVAL获取远程并计算落后提交数的频率30m
UPDATER_PRUNE成功更新后执行 docker image prune -ftrue
UPDATER_ALLOW_DIRTY允许在检出目录存在本地修改时更新false
UPDATER_STATE_DIR跨重启保存最近任务的位置/var/lib/warmbly-updater
UPDATER_ADDR监听地址:8095

端点

端点身份验证返回内容
GET /admin/instance/update平台管理员,view_analytics运行构建、最新发布、是否可更新、更新器和任务状态;?log=1 包含任务日志
POST /admin/instance/update/check平台管理员,manage_settings立即执行两项检查并返回状态
POST /admin/instance/update/apply平台管理员,manage_settings启动更新任务并返回,可传 {"target": "latest"} 或发布标签;过程中后端会重启

更新器自己的 API,即 GET /status、POST /check 和 POST /update,使用持有者令牌验证,只面向后端。

检查发现的问题

两项实例健康状态检查与本页相关:

  • update_available,信息级:存在新版本,显示版本及应用方法。
  • updater_unreachable,警告级:已设置 UPDATER_URL,但该地址没有响应,因此按钮无法工作。请启动更新器、修正地址,或删除该变量并手动更新。

在其他主机上运行工作节点

本页针对控制平面。通过面板安装的远程工作节点保留自己的每日自更新定时器,以及节点页面上的拉取最新版本并重启操作;参见日常运维。

本页目录