官方頁面把 OpenShip 部署流程拆成 5 個階段,並宣稱每次部署都是不可變快照、舊版本可供回滾;但「平台顯示回滾成功」不代表你的業務已經恢復。(openship.io)
症狀:控制台顯示回滾完成,舊程式卻無法讀取新資料庫,或請求看似恢復、後台任務卻重複執行。
最快解法:上线前同時驗證舊產物可啟動、舊設定可恢復、資料庫變更向後相容、實際流量已切換,而且佇列任務沒有重複副作用。只要存在破壞性遷移,就把應用程式回滾與資料恢復拆成兩套流程。
這篇適合準備把 OpenShip 用於正式生產部署的 AI SaaS 團隊,也適合需要建立回滾證據與發布審批流程的運維人員。
如果你的服務包含資料庫、Worker、串流回應、WebSocket 或 Agent 工具呼叫,下面的驗收項目不應省略。
先把「回滾成功」定義成可審批的結果
最常見的誤判,是把三件不同的事混在一起:
- 控制台狀態成功:平台完成版本切換,部署記錄顯示成功。
- 容器啟動成功:舊版本映像可以建立新實例,啟動命令、相依套件和連接埠都正常。
- 使用者請求恢復:登入、付款、AI 推論、串流輸出等關鍵路徑能得到正確結果。
你需要在發布記錄中先寫清楚四項內容:恢復目標、關鍵介面、資料完整性要求,以及可以接受的降級範圍。不要先填一個漂亮的恢復時間,再倒推驗收結果;所有時間目標都應來自專案要求或你自己的演練記錄。
測試對象:控制台狀態、關鍵 HTTP 介面、串流介面和資料寫入結果。
證據位置:部署 ID、回滾前後的請求記錄、錯誤日誌、資料比對結果。
通過標準:平台狀態、容器狀態和業務請求三層結果一致。
失敗動作:先停止擴大流量,再由發布負責人決定重新回滾、維持現版本,或啟動資料恢復流程。
舊版本產物必須能脫離殘留容器重新啟動
OpenShip 官方頁面描述了不可變部署快照、舊版本保留與一鍵回滾能力;這可以證明平台具備版本切換機制,但不能證明你的舊版本仍然擁有完整的執行條件。(openship.io)
驗收時不要只在原有容器上按回滾。你應該按以下順序操作:
- 記錄目標版本的 commit、映像標籤或部署識別碼。
- 確認舊映像仍可取得,啟動命令與工作目錄沒有依賴臨時檔案。
- 在隔離環境建立一個新的實例,而不是重啟原本留下的容器。
- 檢查應用程式啟動記錄、監聽連接埠和依賴服務連線。
- 保存回滾前後的部署記錄,讓其他人可以重現相同版本。
OpenShip 回滾會不會恢復舊的環境變數?
不能只根據「版本回到舊版」推斷設定也會回到舊版。你必須比較回滾前後實際注入的環境變數版本、設定來源、更新時間與權限。敏感值只記錄雜湊、版本號或更新時間,不能把金鑰直接寫入測試記錄或文章範例。
官方 API 文件顯示,部署可以透過介面查詢專案與部署狀態;你可以把部署識別碼、版本識別碼和設定版本一併放進交付記錄,避免只截取控制台畫面。(openship.io)
設定、金鑰與外部服務要分開驗收
應用程式回到舊版本,但環境變數仍指向新服務,是生產回滾最容易被忽略的邊界。例如舊版程式預期使用舊 API 路徑,新設定卻把請求送往新介面;又或者舊版需要的金鑰權限已被撤銷,容器因此能啟動、實際功能卻全部失敗。
請建立一份不含秘密內容的設定清單,至少包括:
- 設定名稱與版本識別碼;
- 外部 API 網址和資料庫連線目標;
- 金鑰有效狀態與所需權限;
- Worker、排程器和主程式是否使用同一套設定;
- 回滾後是否需要重新載入或重啟實例。
安全指引提醒,秘密不應硬編碼在映像、Docker 建置參數或一般設定檔內;環境變數也可能出現在記錄、程序檢視或系統傾印中。(cheatsheetseries.owasp.org)
測試對象:應用程式、Worker、外部 AI API、資料庫和物件儲存的實際連線設定。
證據位置:設定版本清單、金鑰權限記錄、啟動日誌中的非敏感設定摘要。
通過標準:舊程式使用預期的外部服務,且所有必要金鑰仍具備最低必要權限。
失敗動作:禁止把新設定硬塞給舊程式;先恢復正確設定版本,再重新啟動實例並重做關鍵請求。
資料庫遷移決定你能否安全回到舊程式
資料庫已經遷移後,還能不能回滾 OpenShip 應用程式?
可以,但前提是舊程式仍然能讀取目前 Schema,而且新欄位、新約束或資料格式沒有破壞舊版的假設。應用程式回滾本身不等於資料庫自動恢復;如果需要把資料庫也退回舊狀態,必須另外提供備份、時間點恢復或匯出匯入的獨立證據。
把資料庫變更分成三類:
- 可逆遷移:有明確的 down migration,且回退不會遺失已寫入資料。
- 向後相容遷移:先新增欄位或表格,舊版可以忽略,新版再逐步使用。
- 破壞性遷移:刪除欄位、改變資料型別、收緊約束或重寫資料,舊版可能無法讀取。
資料庫官方文件指出,ALTER TABLE 的不同操作可能要求不同鎖定層級;刪除欄位也可能連帶移除相依索引或約束。這就是為什麼「程式碼可以回到舊版」不能被當作「資料也可以回到舊版」。(postgresql.org)
你可以參考資料庫備份策略指南,但正式驗收仍要把以下內容放進專案證據:
- 遷移前後的 Schema 輸出;
- 舊版程式對目前 Schema 的讀取測試;
- 寫入、更新和查詢結果的比對;
- 備份檔案的實際恢復測試;
- 破壞性遷移發生時的資料恢復負責人。
注意:如果只做過「回到舊映像」而沒有測試備份恢復,就只能宣稱應用程式回滾成功,不能宣稱整個系統已恢復。
健康檢查通過後,還要驗證真實流量
健康檢查只回答「實例是否符合檢查條件」,不一定回答「使用者能否完成任務」。OpenShip 頁面列出健康檢查、流量路由、連線排空和 WebSocket 等能力,但零中斷仍應以你的服務實測為準,不能直接把平台功能描述改寫成本站結論。(openship.io)
OpenShip 回滾期間怎樣避免請求中斷?
先讓舊版本新實例通過健康檢查,再切換流量;對串流回應和 WebSocket,還要觀察既有連線是否被排空、是否收到截斷內容,以及重試是否造成重複提交。
至少執行以下測試:
- 用未登入請求測試一般 HTTP 介面。
- 用真實測試帳戶測試登入、核心操作和資料寫入。
- 送出一次串流 AI 請求,確認首段輸出、完整結束和錯誤處理。
- 建立一條 WebSocket 或長連線,觀察切換前後是否斷線。
- 比對切換前後的錯誤記錄、回應狀態和請求 ID。
如果健康檢查通過、但關鍵介面仍回傳錯誤,結論應是「禁止接收流量」,而不是「回滾完成」。
後台任務要用副作用證明沒有重複執行
為什麼後台任務在回滾後會重複執行?
常見原因是新舊 Worker 在短時間內同時存在、排程器重新觸發,或訊息已被取出但狀態尚未可靠寫回。對 AI Agent 來說,重複工具呼叫可能造成重複付款、重複寄信或重複寫入外部系統。
測試時不要只看 Worker 顯示「運作中」,而要追蹤:
- 任務 ID 是否全程不變;
- 佇列取出、開始、完成和失敗狀態;
- 外部副作用是否只發生一次;
- 重試時是否使用冪等鍵;
- 發現重複消費後,誰負責停止 Worker、標記任務和補償資料。
測試對象:排程任務、訊息佇列、工具呼叫和外部寫入。
證據位置:任務 ID、佇列記錄、Worker 日誌、外部服務回應和資料庫狀態。
通過標準:同一任務可以重試,但不可重複產生不可逆副作用。
失敗動作:立即暫停排程或消費者,保留重複任務清單,再由資料負責人決定取消、回補或人工核對。
生產前用清單完成一次完整演練
你可以把下面清單附在發布工單中,逐項勾選,不要只由操作者口頭確認:
- [ ] 已記錄回滾目標版本、部署識別碼和映像識別碼。
- [ ] 已在新實例上啟動舊版本,沒有依賴殘留容器。
- [ ] 已保存啟動命令、相依套件和部署日誌。
- [ ] 已核對環境變數版本、外部 API 網址和金鑰權限。
- [ ] 已用舊程式讀取目前資料庫 Schema。
- [ ] 已分辨向後相容遷移與破壞性遷移。
- [ ] 已完成備份檔案的獨立恢復測試,或明確標記尚未具備恢復證據。
- [ ] 已驗證一般 HTTP、串流回應與長連線。
- [ ] 已觀察流量切換前後的錯誤日誌和請求結果。
- [ ] 已測試排程、佇列、Worker 和 Agent 工具呼叫。
- [ ] 已寫明重複消費、資料不相容或流量未切換時的停止動作。
- [ ] 已指定發布負責人、回滾負責人和資料恢復負責人。
用三張表形成最後的發布判斷
| 驗收指標 | 測試對象 | 證據位置 | 通過標準 | 失敗動作 |
|---|---|---|---|---|
| 舊產物可啟動 | 新建立的舊版實例 | 映像識別碼、啟動日誌 | 可獨立啟動並連線必要服務 | 停止流量切換,補齊產物或依賴 |
| 設定一致性 | 環境變數、金鑰、外部 API | 設定版本與權限摘要 | 舊程式使用正確設定 | 恢復設定版本後重新部署 |
| 資料庫相容 | 舊程式與目前 Schema | Schema 比對、讀寫測試 | 查詢與寫入結果符合預期 | 禁止上線,啟動資料評估 |
| 流量連續性 | HTTP、串流、WebSocket | 請求 ID、錯誤日誌 | 關鍵請求完成,連線沒有異常截斷 | 暫停切流並維持可用版本 |
| 任務冪等性 | Worker、佇列、排程 | 任務 ID、外部副作用 | 同一任務不重複產生副作用 | 停止消費者並執行補償 |
| 資料庫遷移類型 | 舊程式能否直接回滾 | 必須補充的證據 | 建議結論 |
|---|---|---|---|
| 只新增向後相容欄位 | 通常可以,但仍須實測 | 舊程式讀寫測試 | 可考慮上線 |
| 有明確可逆遷移 | 視回退腳本和資料寫入而定 | 回退腳本、資料比對 | 限制上線 |
| 刪除欄位或改變型別 | 不應直接假設可以 | 備份恢復、資料轉換驗證 | 禁止直接回滾 |
| 已產生不可逆外部副作用 | 程式可回滾不代表業務可回復 | 任務清單、補償方案 | 應用與資料恢復分離 |
| 發布結論 | 必要條件 | 交付記錄必須包含 |
|---|---|---|
| 通過 | 舊產物、設定、資料、流量、任務五類證據完整 | 版本、測試結果、負責人 |
| 限制上線 | 有已知限制,但核心請求與資料完整性可接受 | 限制範圍、監控方式、撤回條件 |
| 禁止上線 | 破壞性遷移未驗證、任務可能重複,或關鍵請求未恢復 | 失敗證據、停止動作、資料恢復方案 |
與手動維護多套腳本相比,OpenShip 的不可變快照、舊版本保留和集中式部署記錄,確實能讓版本切換比較容易追蹤;但它仍不能代替資料庫恢復、設定版本管理和任務冪等設計。(openship.io)
如果你目前依賴單一伺服器上的殘留容器、人工修改環境變數,或只用「容器有回應」判斷發布成功,真正的缺點是證據分散、回滾邊界不清,而且資料與後台任務很難在事故後重建。這種情況下,先把一次完整回滾納入上线前演練,比直接把一鍵按鈕交給生產環境更重要。若本地建置端無法持續在線,或團隊缺少隔離的驗收環境,可以再參考雲端 Mac 建置與臨時驗收環境,把建置、測試和回滾演練分開,減少正式環境被測試動作干擾的風險。需要確認 Kvmzen 的臨時環境安排時,也可先查看服務說明與支援入口。
