FR-172 · 說明 · 循序圖
主系統升級、主系統發動 Agent 升級、Agent 主控台發動
三張循序圖加兩張逐步表,說明按下更新後每一步誰在跑、跑哪支程式、畫面看到什麼。與 FR-175 機制問答「線上升級執行流程」同一份內容;那邊另有補問「升級觸發機制:更新單與主機監看服務」。
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
autonumber
participant B as 瀏覽器(更新中心)
participant N as 前門 guidant-fe(nginx)
participant M as 後端 guidant-api/worker
participant S as 更新站+R2
participant H as 主機 systemd(root)
participant P as 進度檔 upgrade-progress.json
B->>M: 立即檢查(另有每日排程)
M->>S: /v1/check product=host
S-->>M: 新版、簽好的清單、三段說明
B->>M: POST …/apply「更新到 X」
Note over B: 全頁遮罩,只顯示進度
M->>S: /v1/download-url(15 分鐘預簽網址)
M->>S: 下載整包與 ops 小檔(背景工作、可續傳)
M->>M: 本機公鑰驗章、比對雜湊
M->>H: 寫更新單 upgrade/orders/<job>.json
H->>H: guidant-upgrade-order.path 看到檔 → .service → guidantai upgrade --from-order
H->>H: 重驗包與章(容器寫的單不全信)
H->>P: 第 0 步 換新版維運指令與維護頁
H->>P: 第 1 步 預檢、第 2 步 放 draining 旗標等工作歸零
Note over M: worker 不撿新單、不推新工作給 Agent;API 照常
rect rgb(236,236,236)
Note over B,P: 第 3~6 步:後端與資料庫停機,畫面由前門維護頁提供
H->>H: 第 3 步 停 api/worker/socketio/db,複製資料庫
B->>N: 輪詢拿到 502 → 整頁 reload
N-->>B: 探後端不通 → 送維護頁
B->>N: 每 3 秒 GET /upgrade-progress.json
N->>P: 直接讀唯讀掛載的檔(不經後端)
H->>H: 第 4 步 在複本 load 映像、跑 migration
H->>H: 第 5 步 用複本起新版,打 version/login/三支 API
H->>H: 第 6 步 改 .env、換目錄、依序起服務,最後重建 fe
end
H->>P: 第 7 步 清理舊映像、舊快照;status=succeeded
N-->>B: 探後端通了 → 跳回更新中心 ?upgraded=1
M->>P: 排程每分鐘讀:同步單終態、補寫系統日誌、回報更新站
M->>M: agent-bundles 有相容新版 → 自動建 Agent 推送列(接圖 2)
rect rgb(253,236,236)
Note over B,P: 任一步失敗或逾時
H->>H: 第 8 步 rollback:.env 寫回舊值、起舊版
H->>P: rolled_back(退回也失敗寫 rollback_failed)
end
| 步驟 | 誰在跑、跑哪支 | 做什麼 | 使用者看到 |
|---|---|---|---|
| 按下「更新到 X」 | 後端 product_update_flow.py、package_downloader.py、package_verifier.py、upgrade_order.py |
沒包就先下載(背景工作),用本機公鑰驗章與雜湊,寫更新單 upgrade/orders/<job>.json。後端到此為止,不碰 docker |
全頁遮罩、八步清單,每 3 秒問 GET …/status |
| 單落地 | 主機 guidant-upgrade-order.path → .service → lib/upgrade_order.sh → lib/upgrade_runner.sh |
撿單就刪單,重驗包與章、確認版號比現行新(測試機開同版開關時同版也放行) | 「已送出」 |
| 0 換維運指令 | 主機 self_replace.sh |
從 ops 小檔取新版 guidantai、lib/、維護頁;exec 新版續跑 |
照常 |
| 1 預檢 | 主機 upgrade_preflight.sh |
簽章、雜湊、docker、資料庫、磁碟等;不過就停,系統沒動 | 照常 |
| 2 停接新工作 | 主機 upgrade_drain.sh;後端 core/maintenance_gate.py |
放 draining 旗標:worker 不撿新單、不推新工作給 Agent;等進行中的歸零 |
照常操作,新工作先排隊 |
| 3 停服務、複製資料庫 | 主機 upgrade_db_copy.sh |
停 api/worker/socketio/db(fe、redis、seaweedfs 不停),複製 pgdata → pgdata-next |
維護頁(前門 nginx 直接讀進度檔) |
| 4 在複本上升級 | 主機 upgrade_apply_on_copy.sh |
解包、load 映像並核雜湊、db 指到複本、init 容器跑 migration、補設定 | 維護頁第 4 步 |
| 5 健康檢查 | 主機 upgrade_health.sh |
用複本起新版 api,打 version、login、三支 API | 維護頁第 5 步 |
| 6 換接 | 主機 upgrade_switch.sh |
改 .env 版號與資料庫目錄、搬目錄、依序起服務,最後重建 fe;寫 last-switch.json |
fe 重建那幾秒看不到畫面,之後跳回更新中心 |
| 7 清理 | 主機 upgrade_cleanup.sh |
刪舊映像、只留一代資料庫快照;升級成功後 incoming/ 只留清單 |
新版畫面 |
| 換接後一分鐘內 | 後端排程 core/scheduler_update.py |
同步單終態、補寫系統日誌 6239~6248、回報更新站;有相容 Agent 新版就自動建推送列 | 現行版與「上次更新完成時間」 |
| 失敗或逾時 | 主機 upgrade_rollback.sh |
停新版、.env 寫回、起舊版;第 0~2 步失敗系統沒動只記 skipped |
維護頁「已退回」或「需主機管理員」 |
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
autonumber
participant B as 瀏覽器(更新中心 Agent 區)
participant M as 主系統後端
participant S as 更新站+R2
participant A as Agent 容器(8443)
participant H as Agent 主機 systemd(root)
participant C as Agent 主控台(8444)
B->>M: 勾選 N 台,「更新選取的 N 台到 X」
alt 手上沒有包,或手上的包比更新站查到的舊
M->>S: 下載 Agent X(背景工作,畫面有進度、可取消)
M->>M: 驗 agent_release_manifest 章與雜湊 → agent-bundles/X/
Note over M: 下載中再有人按更新,併入待推清單(各記操作者)
end
M->>M: 建推送列:先推 1 台,成功再推其餘
M->>A: 直推 POST /update {版號, sha256, 大小}(mTLS+60 秒 JWT)
Note over A: 進入維護模式:停收新工作
C->>A: 每 30 秒問狀態 → 拿到 in_progress → 整頁鎖住
A->>M: GET /agents/update/bundle 下載包(可續傳)
A-->>M: 事件 update_download
A->>A: 核大小與雜湊,寫升級單 agent-upgrade-order.json
H->>H: guidant-agent-upgrade-order.path 看到單 → upgrade-host order
H->>H: 從現行 Agent 映像讀出 upgrade_order.sh,用舊版 Agent 驗新版程式樹的章
H->>H: 預檢 → 等工作做完 → 換上新版設定 → 重建容器 → 健康檢查 → 清理
A-->>M: 事件 update_step(每一步,失敗帶錯誤輸出末 20 行)
A-->>M: 新容器起來:事件 update_result+上傳升級紀錄
M-->>B: 每台八步進度與結果;整批成功後清用不到的包
C->>A: 版本換了 → 整頁重新載入回原頁(不必重登)
| 畫面那一格 | 誰在跑、跑哪支 | 做什麼 |
|---|---|---|
| 等 Agent 接手 | 主系統 agent_rollout_service.py、core/plugins/_agent_commands.py;Agent sync/api/cmd_update.py |
主系統直推 POST /update;Agent 收下即進入維護模式(停收新工作) |
| 下載更新包 | Agent sync/app/update_sync.py;主系統 GET /agents/update/bundle |
向主系統下載包、核大小與雜湊,送 update_download 事件 |
| 解開更新包 | Agent 主機 upgrade_order.sh(從現行 Agent 映像讀出來跑) |
撿升級單、預檢版號(同版只有開關開才放行)、磁碟、解包、用舊版 Agent 驗新版程式樹的章 |
| 預檢 | Agent 主機 upgrade_runner.sh |
主系統位址必須 https、工具差異提醒、空間 |
| 停接新工作,等進行中的做完 | 同上、upgrade_guard.sh |
等執行中的掃描做完 |
| 換上新版 | 同上 | 先備份 .env 與 compose 檔,再換 compose 檔與映像版本 |
| 啟動新版與健康檢查 | 同上 | 重建容器、確認版本與資料 |
| 清理 | 同上 | 維運指令換新;只記警告,不影響結果 |
| (結果) | Agent update_events.py、update_log_upload.py |
新容器起來送 update_result、上傳升級紀錄;換版後失敗自動還原 .env 與 compose 檔 |
%%{init: {'theme':'base','themeVariables':{'primaryColor':'#E2F0F1','primaryTextColor':'#14201F','primaryBorderColor':'#0E7C86','secondaryColor':'#EEF2F3','secondaryTextColor':'#14201F','tertiaryColor':'#FBFCFC','tertiaryTextColor':'#14201F','lineColor':'#4A5A5C','textColor':'#14201F','mainBkg':'#E2F0F1','nodeBorder':'#0E7C86','nodeTextColor':'#14201F','edgeLabelBackground':'#FBFCFC','titleColor':'#14201F','clusterBkg':'#FBFCFC','clusterBorder':'#E4EAEB','actorBkg':'#E2F0F1','actorTextColor':'#14201F','actorBorder':'#0E7C86','actorLineColor':'#C7D1D2','signalColor':'#4A5A5C','signalTextColor':'#14201F','labelBoxBkgColor':'#EEF2F3','labelBoxBorderColor':'#C7D1D2','labelTextColor':'#14201F','loopTextColor':'#14201F','noteBkgColor':'#F6EBD5','noteTextColor':'#14201F','noteBorderColor':'#9C6B12','activationBkgColor':'#EEF2F3','activationBorderColor':'#C7D1D2','sequenceNumberColor':'#FFFFFF'}}}%%
sequenceDiagram
autonumber
participant O as 操作者(Agent 主控台 8444)
participant A as Agent
participant M as 主系統後端
participant S as 更新站
O->>A: 立即檢查
A->>M: POST /agents/update/check(通行證+DPoP)
M->>S: 查 Agent 版本線(全機 5 分鐘節流)
A->>M: GET /agents/update/available
M-->>A: 有新版 X(主系統手上還沒有包也照報)
O->>A: 更新到 X
Note over O: 按下當下整頁鎖住
A->>M: POST /agents/update/request(操作者名稱)
M->>M: 手上不是最新 → 排下載,推送人記「agent-console:操作者」
M->>A: 下載完直推 POST /update(之後同圖 2 第 7 步起)
rect rgb(236,236,236)
Note over O,S: 與主系統斷線時
O->>A: 離線上傳 .offline.tar.gz
A->>A: 用現行版公鑰驗章 → 雜湊 → 版本 → 磁碟 → 寫升級單(同圖 2 第 12 步起)
end
guidant-fe(nginx)從不停。它探到後端不通就改送維護頁,維護頁每 3 秒直接讀進度檔,不經後端、不經資料庫。/update 起 Agent 就停收新工作,直到換版完成。PRODUCT_UPDATE_ALLOW_SAME_VERSION=1、Agent AGENT_UPDATE_ALLOW_SAME_VERSION=1。出貨範本不帶這兩個鍵,正式環境不會出現。| 想看 | 去哪 |
|---|---|
| 升級觸發機制(更新單、主機 systemd 監看服務) | FR-175 機制問答 · 線上升級執行流程 補問 |
| 程式清單、優化項目、交付物現況 | FINAL-SPEC.md |
| PM 常問的 16 題 | for-pm-qa.md |