GUIDANT AI · 落地版
線上更新機制
出版流程、簽章與加密、升級流程與狀態判斷、服務架構
FR-167 · 2026-10-31 · 技術說明
講者備註
開場一句話:客戶主機從此不用搬檔、不用敲指令;每一版由原廠蓋章,主機不信任任何中間人,升級在資料庫複本上做、失敗自動退回。
這次做了什麼:客戶主機自己升級,原廠只蓋章
以前
- 工程師把 5 GB 安裝包搬到客戶主機
- 登入主機敲指令、人工看 log
- 升級失敗要人工救、停機時間不確定
- 沒有簽章,誰給的包都裝
現在
- 主系統每 6 小時自動問更新站有沒有新版
- 管理員在畫面按「更新」,可立即或排程
- 每一版由決策者本人離線蓋章,主機驗不過就拒裝
- 升級在資料庫複本上做,失敗自動退回,現用資料不動
三個原則:任何版本都不自動裝 · 只維護最新版 · 授權管「能用什麼」不管「能不能裝」
決策定案 D1~D31,見 design.md §3
講者備註
重點:自動化的是「發現與下載」,「裝」永遠要人按。老闆若問為什麼不全自動:因為停機時間是客戶的,不是我們的。
整體架構:四個角色,私鑰只在一個人手上
① 原廠 CI(GitLab)
出包、登記草稿
- Nuitka 編譯、SBOM、弱點掃描
- 算整包 SHA-256
- 傳 R2、向更新站登記草稿
- 沒有私鑰
② 決策者電腦
蓋章、發布
- Ed25519 私鑰,passphrase 加密
- 一次 publish 打一次密碼
- 主力章+備用章離線封存
- 唯一有私鑰的地方
③ 更新站(Cloudflare)
轉交清單、發下載網址
- Worker+D1+R2
- 只存公鑰與蓋好章的清單
- 後台受 Access 保護
- 沒有私鑰
④ 客戶主機
驗章、升級、退回
- 主系統(容器)只寫更新單
- 主機 systemd 跑升級程式
- 公鑰裝在 /etc/guidant/release-keys
- 驗證更新包有沒有被竄改
更新站被入侵的最壞結果:客戶下不到新版。因為它沒有私鑰,改不了任何一份清單,主機驗章就會擋下。
更新站網址 guidantai-update.jedicotech.com · 離線客戶由原廠交付單一離線檔,走同一套驗證
講者備註
老闆最可能問的一句:更新站被打下來會怎樣?答案在底下那行。
出版流程:推一個版號,到客戶看得到新版
① 工程師
推版號
git tag 一個新版
② CI 自動
編譯與掃描
編譯、產 SBOM、弱點掃描紅就停
③ CI 自動
打包上傳
算指紋、傳更新站、登記成草稿(客戶還看不到)
④ 決策者本人
蓋章放行
一條指令、打一次密碼
⑤ 客戶主機自動
看到新版
每 6 小時問一次,通知管理員
人只做兩個動作:推版號、打一次密碼。中間編譯、掃描、打包、上傳、登記全部自動。包先上傳只是存放,狀態是草稿,客戶看不到;決策者蓋章後才變成可下載。
第 ④ 步刻意不能自動:私鑰不放 CI,避免任何人推個版號、或 CI 被打,就能發一版客戶會裝的東西。
給客戶看的說明文字(更新了什麼、影響、建議)隨 release note 一起進更新站,發布後可改。
要撤回某版:後台一鍵下架,客戶端路徑自動繞過它
講者備註
打折處要誠實:測試期 1.27.x 是用測試章、腳本直寫更新站資料庫,正式路徑(CI 登記 → 蓋章放行)出貨前要完整走一次。說明文字目前還是人工填,要接進 CI。
簽章與加密:用在哪三個地方
原廠 CI
出包
算安裝包指紋
① 簽名
Ed25519
決策者電腦
打密碼解開私鑰
對清單蓋章
② 轉交
HTTPS
更新站
驗客戶授權
原樣轉交清單與包
③ 驗證
公鑰驗章+SHA-256
客戶主機
驗證更新包
有沒有被竄改
① 簽名(Ed25519)
私鑰只在決策者電腦,檔案用密碼加密(AES-256)。CI、更新站、客戶都沒有私鑰
② 轉交(HTTPS)
更新站只驗客戶授權是真的(授權中心簽的),清單與包一個字不改地交出去,下載網址 15 分鐘到期
③ 驗證(公鑰+SHA-256)
公鑰隨安裝包裝在主機;先核簽名是原廠的,再算整個檔案指紋對清單,不對就不裝
安裝包本身不加密:內容是公開發行的程式,要防的是「被改」與「冒充原廠」
講者備註
為何用 Ed25519 不用 RSA:金鑰短、驗章快、沒參數可選錯,openssl、Python、Node、瀏覽器都原生支援,與授權中心同一套。
客戶主機拿到更新後、開始升級前:先確認五件事
時機:管理員按「更新」之後、服務停下之前。目的只有一個,不要裝到假的、壞的、不該裝的東西。任何一道不過就停下,系統不動。
| 確認什麼 | 擋住哪種壞事 | 怎麼確認 |
|---|---|---|
| 是原廠簽的 | 有人冒充原廠發一個假更新 | 用主機內存的公鑰核對清單簽名 |
| 檔案沒被改 | 下載途中被換包、或下載不完整 | 整個檔案算指紋對清單(SHA-256) |
| 版本只能往上 | 拿舊版合法的包把系統降回有漏洞的版本 | 包的版號要比現行大,且不低於清單寫的起始版 |
| 主版號相同 | 1.x 的授權裝到 2.x,授權範圍不符 | 包的主版號要等於現行主版號 |
| 主機裝得了 | 裝到一半磁碟滿、資料庫連不上、docker 壞了 | 預檢:空間、資料庫、docker、停機估算 |
為什麼要主機自己驗,不信更新站:更新站在外網,是整條鏈最可能被打的點。它被攻破最多只能「不給」,給不了假的。
離線客戶一樣:原廠交離線檔,管理員上傳,走同一套確認,驗不過即刪。
前兩項在下載完就先驗一次,開始升級時再驗一次;都是機器做,管理員不用操作
講者備註
老闆問「如果公鑰被換掉呢」:公鑰在主機 /etc/guidant/release-keys,root 才改得了;能改那裡的人本來就能對主機做任何事,這不是更新機制要防的範圍。
升級流程:八步,只有中間四步停服務
0
換升級程式
先把自己換成新版的
1
預檢
簽名、指紋、空間、資料庫
2
停接新工作
等進行中的做完
3 · 停服務
複製資料庫
現用那份不再動
4 · 停服務
在複本上升級
載映像、跑 migration
5 · 停服務
健康檢查
用複本起新版實打
6 · 停服務
換接
複本轉正、舊的留快照
7
清理
刪舊映像
第 0~2 步失敗
系統沒動過,只記「這次沒更新」,包留著可以重按
第 3~5 步失敗或逾時
自動退回:丟掉複本、用原本那份把舊版起回來,資料零損失
第 6 步寫完
新版已在服務,不再退回;中途斷電開機自動補做退回
每步有時限;停機只在第 3~6 步,實測 5~6 分鐘;畫面自動切到維護頁、升完自動跳回
講者備註
可以講一句:主系統容器沒有 docker 權限,只會往目錄寫一張更新單;真正動 docker 的是主機上的 systemd,這是刻意的權限切割。
畫面怎麼知道進度:兩個地方記狀態,誰做事誰寫
紀錄一:資料庫裡的更新紀錄
「這次更新走到哪」
下載中 → 已下載 → 已送出 → 升級中 → 結果(成功/失敗/已退回/這次沒更新/已取消)
由主系統後端寫:下載完改「已下載」,按更新改「已送出」並把單子交給主機
紀錄二:主機上的進度檔
「升級八步各跑到哪」
每一步:等待中/進行中/完成/逾時/失敗;整體:進行中/成功/已退回/退回失敗
由主機升級程式寫:每做完一步就改一次;主系統只能讀不能改
| 階段 | 畫面 | 資料從哪來 | 多久問一次 |
|---|---|---|---|
| 按下更新 → 服務停下前 | 更新中心頁 | 問主系統後端,後端把兩份紀錄一起回 | 3 秒 |
| 服務停下 → 換接完成 | 維護頁(自動切換) | 直接讀主機進度檔,不經後端 | 固定輪詢 |
| 換接完成 | 自動跳回更新中心 | 進度檔寫「成功」且後端回應正常才跳 | — |
兩份紀錄的對齊:主系統每分鐘把進度檔的結果抄回更新紀錄;資料庫是歷史,進度檔是現在
講者備註
維護頁一個細節:第 5 步健康檢查會先用複本把新版起來,那時後端已經有回應但還沒換接,所以進度檔寫「進行中」期間維護頁不跳回,避免放人進半套系統。
資料不掉:升級在複本上做,現用資料庫從頭到尾沒動
複本
第 3 步把現用 pgdata 複製成 pgdata-next,migration 全跑在複本;原本那份只讀
健康檢查
第 5 步用複本起新版,實打版本、登入、3 支 API;不過就不換接
自動退回
第 3~5 步失敗或逾時:刪複本、用原本那份把舊版起回來,進度檔記 rolled_back
斷電
開機 boot-check:上次停在第 3 步之後沒收尾就退回;換接已完成就不動
換接之後:舊資料庫留作快照(pgdata-prev-舊版),下一次升級成功才清掉;退回也失敗時 guidantai recover 人工救,維護頁與更新中心都看得到。
實測紀錄(190 測試機):10/30 四次實測,含兩次刻意失敗退回成功、一次退回失敗用 recover 救回;10/31 連升五版全成功。
預檢會算磁碟:需要包大小+解開+資料庫複本,不夠不開始
講者備註
老闆若問「退回要多久」:退回就是把舊容器起回來,資料庫沒動過,實測 1 分內。
整體架構:三個區塊,客戶端一台裝完
客戶端(客戶機房,一台主機)
Guidant AI 主系統
前門與畫面
後端 API
背景工作
即時推播
資料庫 PostgreSQL
快取 Redis
檔案儲存(內建)
證據拆檔沙箱
錯誤追蹤站
升級程式(主機層)
全部跑在一台主機的 docker 上;資料只存在客戶機房;升級程式是主機層的指令,不在容器裡
每 6 小時
HTTPS 出站
原廠端(雲端,只為更新)
更新站
更新站程式(Cloudflare Worker)
版本與回報資料庫(D1)
安裝包儲存(R2)
沒有私鑰、沒有客戶資料;只存公鑰、蓋好章的清單、誰在哪一版
檢測 Agent(選配)
客戶內網另一台,跑弱點掃描與主機檢測;主系統升完可一鍵跟進升級
原廠其他系統
授權中心(簽授權檔,獨立系統)· GitLab CI(出包)· 決策者電腦(蓋章);三者都不與客戶主機直接連線
客戶防火牆只需放行兩個出站網域(更新站、安裝包下載),不需開任何入站;封閉網路可改離線上傳
講者備註
Cloudflare 免費方案就夠:更新站沒有運算負擔,只轉交清單與發下載網址,5 GB 下載直接走 R2。