本 HowTo 與《多可用區網關、探針合併與 Webhook 摘要》互補:彼處主軸為摘要廣播與令牌重疊;此處為流量百分比、不可變技能切片、升級閘門—三台主機即可演練。租戶片段細節見《租戶切片、巡檢合併與 Webhook 失敗摘要》。
OpenClaw 多節點發佈流程(調權重之前)
發佈是跨網關契約,不是單次 git pull。各 Mac 須對齊:openclaw.lock、與 semver 一致的技能目錄、複合就緒路由、以及鏡像的 skills.d。順序:影子樹→Doctor+合併探針綠燈→LB 權重→對等鏡像→稽核一行;跳過影子易導致 LB 仍綠但兩區技能樹已分岔。
- 權威來源:每次升級對應一個 Git tag;工作樹不乾淨則拒絕 launchd reload。
- 並行網關:由一台 writer Mac 打 tag;金絲雀網關先拉取;穩定網關僅在比例閘門通過後再拉取。
- 工作者與通知器:可落後網關一個修訂,但不得超前,否則合併探針會對技能相容性說謊。
#!/usr/bin/env bash
set -euo pipefail
cd /usr/local/share/openclaw-infra
/usr/bin/git fetch --tags origin
/usr/bin/git checkout "refs/tags/${PROMOTE_TAG}"
/usr/bin/shasum -a 256 openclaw.lock | /usr/bin/tee /tmp/lock.sha
/usr/local/bin/openclaw version --json | /usr/bin/tee /tmp/version.json
/usr/bin/diff -q openclaw.lock <(ssh canary-gw "cat /usr/local/share/openclaw-infra/openclaw.lock")
當 diff 為空,才允許動負載平衡權重;若非空請立刻停手,否則你正在製造跨可用區的「分腦」狀態。
流量比例:clustervps 多可用區網關上的金絲雀閘門
金絲雀是一串離散比例:先約5% 新連線到已掛 skills/next 的網關,至少撐過兩次合併探針週期,並看 p95/佇列/錯誤預算(與 Webhook 噪音脫鉤)。Doctor 綠且摘要可接受時,再以約 10–20 個百分點階梯加權。
把負載平衡廠商調權重的 API 或 CLI 寫進 runbook;許多團隊在 Mac 網關前再疊 anycast 或 GeoDNS,建議把廠商呼叫封成 shell function,事故當下可直接貼到值班頻道執行。
配置片段分租戶:技能包版本切片的邊界
切片失敗多因租戶片段合併順序不一致。調 next 指到新 semver 前,先在各網關鏡像 /etc/openclaw/tenants/<tenant>/skills.d/;片段只寫邊界(工具命名空間、模型檔、配額),密鑰改放 /var/db/openclaw/secrets/<tenant> 並用 POSIX ACL,避免 CI 洩漏。
# 各網關在 git tag checkout 之後 sudo install -d -o root -g wheel /etc/openclaw/tenants/acme/skills.d sudo /usr/local/bin/openclaw config lint --tenant acme sudo /bin/ln -sfn "/var/db/openclaw/skills/1.4.2" /var/db/openclaw/skills/next sudo launchctl kickstart -k system/com.openclaw.gateway
金絲雀租戶可把 skills.d/10-canary.yaml 指向 next,生產租戶在稽核核准前仍鎖 current—這是不用整叢集分叉的最小切片模型。
探針合併:Doctor、佇列、摘要與技能 semver
LB 仍打單一 URL,但回應須涵蓋:磁碟 semver 對齊 openclaw.lock、實際吃流量的租戶 Doctor、佇列 SLO。Webhook 摘要僅作合併 JSON 的一欄,不當唯一升級扳機,與純廣播敘事區隔。
#!/usr/bin/env bash
set -euo pipefail
TENANT_CANARY="${TENANT_CANARY:-acme}"
SKILL_PATH="/var/db/openclaw/skills/current"
/usr/bin/readlink "${SKILL_PATH}" | /usr/bin/tee /tmp/skill_path.txt
/usr/local/bin/openclaw doctor --tenant "${TENANT_CANARY}" --json >/tmp/doctor.json
/usr/bin/curl -fsS --max-time 3 "http://127.0.0.1:9099/v1/webhook-digest" -o /tmp/digest.json
/usr/bin/python3 - <<'PY'
import hashlib, json, pathlib
blob = pathlib.Path("/tmp/doctor.json").read_bytes() + pathlib.Path("/tmp/digest.json").read_bytes()
print(json.dumps({"probe_sha256": hashlib.sha256(blob).hexdigest(),"skill_resolved": pathlib.Path("/tmp/skill_path.txt").read_text().strip()}))
PY
Doctor 偏黃但 semver 與摘要仍可接受時,可回傳 status: degraded,讓流量繼續但儀表板拉警報。若 semver 與鎖檔不一致則必須硬失敗—再乾淨的 Webhook 也不應放行該版升級。
回滾:權重、符號連結與 launchd 一口氣還原
回滾須同時:LB 權重回快照,且 skills/current 指回舊 semver;只做一半會新舊流量/技能錯配。兩步完成後 kick launchd,對照稽核檔中的健康快照。
#!/usr/bin/env bash
set -euo pipefail
/usr/bin/scp stable-gw:/var/db/openclaw/audit/last_good_weights.json /tmp/weights.json
./lb_restore_weights.sh /tmp/weights.json
sudo /bin/ln -sfn "/var/db/openclaw/skills/${ROLLBACK_SEMVER}" /var/db/openclaw/skills/current
sudo launchctl kickstart -k system/com.openclaw.gateway
/usr/bin/curl -fsS http://127.0.0.1:8088/readyz | /usr/bin jq .
回滾演練請搭配《跨區並聯叢集:rsync 與建置鎖矩陣》的產物衛生,避免 LB 仍指錯可用區時還在跟 rsync 賽跑。
稽核:資安可用 jq grep 的追加式 JSONL
每步調權重在 writer 網關追加 promotions.jsonl(夜間複寫物件儲存):actor、ticket、前後 semver、權重圖、probe_sha256,方便資安用 jq 對帳。
/usr/bin/printf '%s\n' \
"{"ts":"$(date -u +%Y-%m-%dT%H:%M:%SZ)","actor":"${USER}","ticket":"${TICKET}","from":"1.4.1","to":"1.4.2","weights":"${WEIGHT_BLOB}","probe_sha256":"${PROBE_SHA}"}" \
| /usr/bin/tee -a /var/db/openclaw/audit/promotions.jsonl
稽核來問「改了什麼」時,你應用 jq 篩檔回答,而不是翻 Slack 時間軸。
FAQ:金絲雀優先 vs. Webhook 優先維運
還需要通知器的 digest 嗎? 需要—把它嵌進合併探針,讓值班看見夥伴端系統性中斷。但不要單憑 digest「看起來健康」就放寬流量;semver 與 Doctor 須先達成一致。
只有一個租戶想試新技能? 讓該租戶片段留在金絲雀網關,並以 LB 黏著 Cookie 或標頭把該族群導向金絲雀池,其餘人維持穩定權重。
最少幾台 Mac? 三台 clustervps 仍是最小誠實演練:穩定 AZ-A、穩定 AZ-B,以及先承接比例流量、再由對等鏡像的金絲雀網關。