Skip to content

升级

要升级两个二进制:manager(docker-compose 栈)和 edge(每台主机一个)。两者走同一套概念流程:把新文件 stage 起来,原子换入,如果新版本起不健康就自动回滚到上一版本。

TL;DR

Manager:

bash
VER=v0.7.160
gh release download "$VER" --repo ongridio/ongrid \
    -p 'ongrid-*-linux-amd64.tar.xz*'
sha256sum -c "ongrid-${VER}-linux-amd64.tar.xz.sha256"
tar xf "ongrid-${VER}-linux-amd64.tar.xz"
cd     "ongrid-${VER}-linux-amd64"
sudo ./upgrade.sh

Edge(一次全部,并行,从 UI 触发):

  • Edges → Upgrade all —— manager 向每台已连接 edge 发 MethodFetchPackage,每台从 https://<manager>/edge/ 下载 stage 好的 bundle,stage、重启、swap、跑。失败会在下次启动自动回滚。

或者单个 edge 在 shell 里:

bash
sudo systemctl restart ongrid-edge
# The ExecStartPre runs apply-pending-upgrade.sh which picks up any
# staged bundle and applies it before the new agent starts.

本页其余部分讲清楚这些到底是怎么跑的,你出了问题才好排查。

Manager 升级:upgrade.sh

upgrade.sh 每个发布 tarball 里都有,要在刚解压的新 tarball 里跑。它假设 ${ONGRID_INSTALL_DIR:-/opt/ongrid}/ 下已经有安装。

按顺序:

  1. 预检。 确认 docker + compose v2,找到现存 .env。没有就早退。
  2. 判定新旧版本:从现存 .env 和新 tarball 的 VERSION 文件读。两个都打印——support ticket 时有用。
  3. docker compose down,释放数据卷以便迁移步骤进行。
  4. 重新断言数据目录 owner${ONGRID_DATA_DIR}/ 下(mysql、prom、loki、tempo、grafana、embeddings、qdrant)。镜像 uid 很久没变过,但这是唯一安全的默认——重新断言是幂等的。
  5. 从新 tarball 重新 stage 配置/opt/ongrid/docker-compose.ymlprometheus.ymlprometheus-rules.ymlloki-config.yamltempo-config.yamlgrafana/searxng/nginx.conffrontier.yaml、新的 edge/ 资源、新的 VERSION 文件。.env 保留——upgrade.sh 永不覆盖运维改过的 env。
  6. 加载新 docker 镜像ongrid.tarongrid-web.tar,存在的话还有 frontier.tar)。
  7. .envONGRID_VERSION= 抬版本号,下次 compose-up 才会用新 image tag。
  8. docker compose up -d,用新 env。
  9. 轮询 /healthz 60 秒。
  10. Banner:旧 → 新版本、Web URL、几条下一步好用的命令。

如果在第 8 步之前出错,运维修好根因后可以重跑——upgrade.sh 是幂等的。如果第 9 步失败(/healthz 一直不返回 200),docker compose logs ongrid 里有 manager 的日志告诉你哪坏了。

要零停机就上蓝绿,两台 manager 接负载均衡;OSS 单机安装是升级时短暂停机(约 30-60s)。

升级文件从哪来:make package

这是运维路径——从源码构建(而不是拉 release)时怎么打 tarball。从 ongridio/ongrid 的 checkout 里:

bash
make package

顺序重要;make package 做的事:

  1. fetch-promtail —— 从上游 Grafana release 下载 promtail-<os>-<arch>.zip,解到 bin/<os>-<arch>/promtail。带缓存。
  2. fetch-otelcol —— otelcol-contrib 同理。
  3. fetch-node-exporter —— node_exporter 同理。
  4. fetch-process-exporter —— process_exporter 同理。
  5. build-edge-all —— 交叉编译 ongrid-edgelinux/amd64linux/arm64darwin/amd64darwin/arm64
  6. docker-build —— 构建 ongrid:<version> 镜像。
  7. docker-build-broker —— 从 $FRONTIER_SRC 构建 singchia/frontier:<ver>(本地 image store 里有就跳过)。
  8. docker-build-web —— 构建 ongrid-web:<version>(前端 SPA + nginx)。
  9. build-edge-bundle —— 从散二进制组装 edge-bundle-linux-amd64-<ver>.tar.gz
  10. dist/package.sh —— 把所有东西 stage 到 dist/stage/ongrid-<version>-linux-amd64/docker save 三个镜像,tar.xz 整个目录,算 sha256 sidecar,输出到 dist/out/

输出:

dist/out/ongrid-v0.7.160-linux-amd64.tar.xz
dist/out/ongrid-v0.7.160-linux-amd64.tar.xz.sha256

这就是你 scp 到生产主机并喂给 ./upgrade.sh 的东西。

离线 RAG 模型

BGE embedding 模型不在 package 依赖里——国内网络拉很慢,所以单列一个步骤。如果你想恢复后立刻让 ONGRID_EMBEDDING_PROVIDER=local 可用,在 make package 前先跑一次 make fetch-embedding-model

Edge 升级:ADR-024 stage-then-swap

升级一个 edge 的用户路径是"UI 上点 Upgrade"或 stage 好 bundle 后跑 systemctl restart ongrid-edge。实际发生什么,自顶向下:

1. Manager 触发,edge 拉取

点 "Upgrade all edges"(或单个 edge)时:

  • Manager 从 /opt/ongrid/edge/dist/out/edge-bundle-<arch>-<ver>.tar.gz.sha256install.sh / upgrade.sh 放在那的)。
  • Manager 通过隧道给目标 edge 发 MethodFetchPackage(url=https://<manager>/edge/<bundle>, sha256=<sha>, version=<ver>)
  • nginx 从同一个 /edge/ 目录把 bundle 字节服出去。

2. Edge stage

收到的 edge:

  • 把 bundle 下载到 /tmp/
  • 用 manager 发的 manifest 校验 sha256。
  • 解到 /var/lib/ongrid-edge/.upgrade/incoming/
  • 校验 MANIFEST.txt 的每行 <sha> <mode> <src> <dest>(sha 匹配、src 存在)。
  • 写一个 "ready" marker。
  • 干净退出。systemd 按 Restart=always 重启 unit。

3. systemd 的 ExecStartPre 跑 swap

Unit 里带:

ini
ExecStartPre=-+/usr/local/lib/ongrid-edge/apply-pending-upgrade.sh
ExecStart=/usr/local/bin/ongrid-edge

+ 前缀让 hook 以 root 跑,尽管 User=ongrid-edge- 让脚本缺失/失败时返回 0 不挡 unit,确保升级前的二进制总能启动。

apply-pending-upgrade.sh 按顺序:

  1. Mode 1:自动回滚 —— 如果上次升级跑过但从未写 healthy_markerlast_upgrade_ver 匹配。把每个 <dest>.previous 还原回 <dest>。清 staging 目录。
  2. Mode 2:bundle 应用 —— MANIFEST.txt 每一行:
    • 重新校验 sha256,
    • cp -p $dest $dest.previous(快照用于回滚),
    • 同一文件系统cp $src $dest.new,让最后那次 rename 是 POSIX 原子的,
    • chmod $mode $dest.new
    • mv -f $dest.new $dest
  3. Mode 3:legacy 单文件应用 —— 兼容还没 bundle 升级过的老 edge(只有 agent 二进制,没 manifest)。
  4. 记录 last_upgrade_atlast_upgrade_ver,给下次启动的健康检查用。

然后 ExecStart=/usr/local/bin/ongrid-edge 跑新 swap 过的二进制。

4. 新 agent 上报健康(或不上报)

新 agent 成功连上后:

  • /var/lib/ongrid-edge/.upgrade/healthy_marker,内容是它跑的版本。
  • 经隧道用新版本号 register

如果下次启动时该文件存在且跟 last_upgrade_ver 匹配,apply-pending-upgrade.sh 宣布升级成功,剪掉所有 .previous 释放磁盘,清 staging。

如果不(agent 崩了、连不上 manager、随便什么),下次启动触发自动回滚:每个 .previous 还原、staging 清空、edge 重新跑上一个能跑的版本。运维在 UI 上看得见这件事(触发了升级后 edge 还在上报 "旧" 版本——这是新 bundle 有问题的信号)。

Bundle 不变量

Edge swap 的每个文件都在 bundle 里;bundle 里的每个文件都是自包含的二进制或脚本。这是硬性要求:

  • Agent 二进制ongrid-edge
  • 插件二进制promtailotelcol-contribnode_exporterprocess_exporter
  • Hook 脚本apply-pending-upgrade.sh

插件配置(promtail.yamlotelcol.yaml不在 bundle 里——它们落在 /etc/ongrid-edge/,作为热配置通过隧道下发。这样 agent 升级不会覆盖运维手改的配置。

别把 bundle 烤回 docker 镜像里

源码构建时,bundle 在打包时由 dist/build-edge-bundle.sh主机上构建,不在容器里。ADR-032 强制——把它烤回镜像会双打包 ~120 MB 不可压缩字节,并打破 sha 一致性。

回滚文件在哪

text
/usr/local/bin/ongrid-edge              # current
/usr/local/bin/ongrid-edge.previous     # last known good

/usr/local/lib/ongrid-edge/promtail
/usr/local/lib/ongrid-edge/promtail.previous

...etc.

/var/lib/ongrid-edge/.upgrade/
  last_upgrade_at                       # ISO timestamp
  last_upgrade_ver                      # version string
  healthy_marker                        # written by the new agent

触发升级后的一组启动序列:

text
boot 1 (pre-upgrade):
  apply-pending-upgrade.sh sees nothing staged; exit 0
  ongrid-edge v0.7.159 runs

(manager pushes bundle, edge stages it, edge exits clean)

boot 2 (apply):
  apply-pending-upgrade.sh
    mode 1: no healthy_marker yet, but no last_upgrade_at either → skip
    mode 2: applies bundle. /usr/local/bin/ongrid-edge.previous = v0.7.159
                            /usr/local/bin/ongrid-edge        = v0.7.160
            writes last_upgrade_at, last_upgrade_ver=v0.7.160
            clears healthy_marker
  ongrid-edge v0.7.160 runs
  v0.7.160 connects, writes healthy_marker=v0.7.160

(reboot, e.g. host updates)

boot 3 (settle):
  apply-pending-upgrade.sh
    mode 1: last_upgrade_ver=v0.7.160, healthy_marker=v0.7.160 → success
            prunes all .previous files
            clears last_upgrade_at, last_upgrade_ver
  ongrid-edge v0.7.160 runs

失败场景:

text
boot 2 (apply):
  apply-pending-upgrade.sh: applies bundle as above
  ongrid-edge v0.7.160 crashes immediately (e.g. config drift)
  systemd restarts repeatedly per Restart=always

boot 3 (rollback):
  apply-pending-upgrade.sh
    mode 1: last_upgrade_ver=v0.7.160, healthy_marker missing
            → roll back: restore .previous over each dest
              (ongrid-edge.previous → ongrid-edge, etc.)
            : > last_upgrade_at, rm -rf incoming/
  ongrid-edge v0.7.159 runs again (working)

降级

Manager 降级:解压老 tarball,在里面跑 ./upgrade.sh。只要中间的版本没做过 DB schema 迁移就行。降级前查发布说明里的 "breaking schema change" 标注。

Edge 降级:UI 上"升级"到老 bundle 版本。Manager 逻辑不关心版本号往哪个方向走。

接下来

  • 参考 / env —— 各版本之间默认值会变的环境变量名。
  • 离线安装 —— manager 自己也没网时,如何把文件镜像到私有 webserver 让 apply-pending-upgrade.sh 仍能拉 bundle。