知識與實務

商業實務・AI 應用・人才發展

AI 工作實務

CD 發布演練:驗證 Artifact 雜湊、切換版本與失敗回滾

發布流程真正需要回答的,是目前上線哪一份產物、驗收失敗會發生什麼,以及能否回到已知可用版本。這份練習用 Python、暫存目錄與本機 HTTP 服務,完成產物雜湊檢查、版本切換、故障後自動復原和明確回滾。

CD 從產物到核准節點及部署環境的概念

發布流程真正需要回答的,是目前上線哪一份產物、驗收失敗會發生什麼,以及能否回到已知可用版本。這份練習用 Python、暫存目錄與本機 HTTP 服務,完成產物雜湊檢查、版本切換、故障後自動復原和明確回滾。

專題編輯:Derek Chou|AI 技術與架構編輯 · 文件核對 2026.11.09

CD 從產物到核准節點及部署環境的概念

從治理清單走到可執行的發布練習

如果你正在釐清審批角色、驗收回執或 CI/CD 管理關卡,可以先讀CI/CD 發布、讀回與回滾檢核。本文接續做一件更具體的事:讓「錯誤版本不可留在線上」成為可以故意觸發並觀察的程式行為。

Continuous Delivery 著重讓變更維持可發布狀態,正式上線仍可保留人工決定;Continuous Deployment 則進一步把通過條件的變更自動部署到正式環境。兩者不能只靠 workflow 檔名分辨。AWS 對持續交付的說明

本練習是一個發布機制的縮小模型:建立 ZIP 產物、驗證 SHA-256、放入版本資料夾、切換 current 指向,再以 HTTP 讀回版本。沒有雲端帳號、網站寫入、正式資料庫、真實客戶或 production 權限。你能從中學會辨識發布失敗與復原結果;不能把練習通過寫成公司的雲端部署、核准或災難復原已完成。

開始前,先把「同一份產物」說清楚

常見的不確定性出現在兩次建置之間:CI 測了一份程式,部署階段又重新抓取依賴、重新打包,最後上線的位元組未必相同。此練習建立一次 ZIP,之後的 staging 與 promotion 都使用該 ZIP 內的同一份 release.json,不在發布時重新 build。

SHA-256 可以幫助確認內容是否符合預期,但雜湊值本身不會證明來源可信。若攻擊者能同時換掉 ZIP 和預期雜湊,檢查仍可能成功。正式環境需要把產物、來源提交、受信任的建置紀錄與核准決定連在一起;有需要時再加入簽章或 attestations。本文只驗證已給定預期雜湊的位元組一致性,沒有實作完整供應鏈信任機制。GitHub 產物來源證明說明

步驟一:準備隔離環境與練習檔

使用 macOS 或 Linux、Python 3.12 或相容的 Python 3 環境,並允許開啟本機 loopback port。程式使用標準函式庫,不需要 pip 套件、雲端金鑰或網路部署工具。Windows 的 symbolic link 權限與檔案替換行為可能不同,本文沒有提供 Windows 環境的驗收保證。

下載完整練習檔,解壓後包含:

release_lab.py
delivery.yml
README.md

進入該資料夾後執行:

python3 --version
python3 release_lab.py --output evidence

程式會建立自己的暫存目錄與空閒本機 port,結束時關閉服務並清理暫存發布目錄;evidence/ 保留結果 JSON 與三份合成產物,方便重算雜湊。不要把此程式的暫存路徑改成現有網站根目錄;這不是可直接接上正式站的通用部署工具。

若環境禁止本機 listener,會看到權限或 bind 錯誤。這表示環境不能執行本練習,不能改寫成測試通過。可改在允許本機服務的隔離開發環境或 CI runner 執行,並保存實際使用環境的證據。

步驟二:先驗證 SHA,再放入 staging 版本目錄

build() 建立 v1、v2、v3 的 ZIP;stage() 先比對檔案雜湊,接著確認 ZIP 只含預期的 release.json 並通過 CRC。這個單一檔案白名單同時讓範例避免接受任意路徑或額外檔案,不使用未檢查的整包解壓。

核心順序為:

if digest(artifact) != expected_sha:
    raise ValueError("Artifact SHA256 mismatch; nothing promoted")
with zipfile.ZipFile(artifact) as archive:
    if archive.namelist() != ["release.json"]:
        raise ValueError("Unexpected archive")
    content = archive.read("release.json")

內容還須符合此練習的版本命名與 ready 欄位,才能寫入 releases/v1 等目錄。這裡的 ready 是合成範例資料,並非替代真實 CI 測試回執;正式流程不能只相信產物自己寫著「我已測試」。

演練會故意把 v2 的預期 SHA 設成錯誤值。正確結果是 staging 拒絕,HTTP 仍回傳 v1;不能只檢查函式丟出例外,卻沒有確認現行服務是否被改動。這個負面案例用來證明驗證發生在版本提升之前。

步驟三:切換指向後,以 HTTP 確認版本

驗證完成的版本各自放在獨立資料夾。switch() 先建立 current.next symbolic link,再以 os.replace() 替換 current。在符合條件的同一檔案系統上,這個替換操作提供原子性的名稱切換;它不等於跨主機、跨資料庫的分散式交易,也不保證正在處理的請求完全不中斷。Python os.replace 文件

練習的 HTTP handler 每次從 current/release.json 讀取版本,因此 v2 提升成功後,GET /health 應同時符合 HTTP 200 與 version=v2。只看 200 不夠,因為舊版或錯誤路由也可能回 200;只看磁碟 symbolic link 也不夠,因為真實服務可能仍載入舊程序或快取。

本例沒有外部負載平衡器或 CDN,所以這個讀回只驗證本機服務。正式系統需根據架構檢查真正對外入口、版本標記及關鍵業務路徑,並考慮健康檢查與使用者流量的差異。

步驟四:讓新版本故障,再驗證回滾

v3 的 SHA 是正確的,格式也符合本練習契約,但它故意在 HTTP 階段回 503。這代表「位元組正確」和「服務可用」是不同門檻。promote() 先記住原有版本,再切換與讀回;若狀態碼或版本不符,或讀回發生連線、逾時、JSON 解析例外,就恢復先前的指向,再以 HTTP 確認舊版本。若回復後仍無法讀回,程式會明確標示「指向已恢復,但 HTTP 復原未確認」,不冒稱服務已恢復。初次發布若沒有前版可回復,則移除失敗版本的 current 指向並回報沒有前版。

腳本接著確認 HTTP 已恢復為 v2,而不是只相信程式執行過 rollback。另以明確標示的故障注入分別觸發連線、逾時與 JSON 例外;注入只替代第一次驗收,回復後仍透過真實本機 HTTP 讀回。這些案例驗證例外處理,沒有模擬真實網路中斷的全部行為。最後再明確切回 v1,重新驗證 v1 的 HTTP 回應。正常完成時,evidence/result.json 應包含下列七項檢查,終端輸出 CD_LAB_PASS:

演練情境需要看到的結果
初次發布 v1SHA 一致,HTTP 200 且版本為 v1
v2 的預期 SHA 錯誤拒絕 staging,HTTP 保持 v1
合法提升 v2使用原產物,HTTP 200 且版本為 v2
v3 提升後回 503發布失敗,自動恢復並讀回 v2
注入連線、逾時與 JSON 驗收例外三種例外各自恢復 v2,並使用真實 HTTP 確認
初次發布驗收失敗移除 current,明確回報沒有前版可回復
明確回到 v1HTTP 200,版本確實為 v1

只要其中一項不符,程式會以非零狀態結束;不會因為曾經產生 ZIP 或曾成功切換路徑就宣告整體完成。結果 JSON 亦保存 Python 版本、平台與產物 SHA,讓下一位接手者能知道這次證據涵蓋的環境。

回滾程式版本,為什麼還不能保證資料安全?

本練習沒有資料庫,因此沒有證明資料遷移可回復。真實系統若先刪掉舊欄位或改寫資料格式,回到舊程式也可能無法讀取資料;還有訊息佇列、外部支付與已寄出的通知等副作用,不會隨程式版本自動消失。

對含資料遷移的服務,應先寫明新舊版本可同時接受哪些資料,再規劃擴充、切換與移除的順序。這是工程設計建議,實際策略取決於資料模型、交易與業務要求。發布計畫至少需要區分:哪些可用程式回滾處理、哪些要前向修復、哪些須由備份還原,以及每條路徑可能造成的資料損失。

同樣地,灰度發布與藍綠部署都涉及真實流量控制;本機切換一個 link 沒有演練流量比例、跨節點一致性、連線排空或觀察時間。不要把縮小模型的成功外推成已驗證零停機部署。

放進 GitHub Actions 時,核准條件在哪裡?

附件的 delivery.yml 只執行這個隔離演練並保存 evidence artifact。它沒有 production environment,也不讀取部署機密。若把它複製到專案,需將 workflow 放入 .github/workflows/,並讓 run 路徑對應 release_lab.py 的實際位置。

要建立真實部署核准,不能只寫 environment: production。GitHub 的 environment 必須設定適用的保護規則;若 workflow 引用尚不存在的 environment,可能建立一個沒有 reviewers 或 secrets 的環境。保護功能亦受方案和 repository 可見性影響,應核對自己帳號實際可用的能力。GitHub environment 文件

正式部署前,應以具體的產物版本與變更摘要供核准者審閱,並在既有權限模型中驗證該角色能否批准、是否禁止自我核准、哪個分支可部署。本文沒有替讀者建立或測試任何這類帳號設定,練習的自動版本切換也不是人工核准紀錄。

下一次發布,可以直接帶走的驗收欄位

在實際專案中記錄來源提交、產物 SHA、部署目標、前一版本、啟動時間、HTTP 或業務驗收結果、失敗原因及恢復後版本。沒有觀察到的欄位保留待核,不要把 pipeline successful 擴大解讀成全部使用者都已取得正確結果。

這套練習讓發布具備一個可重現的失敗路徑:錯誤產物在切換前被拒絕,可驗證但不可用的新版本在切換後被復原。當團隊能留下兩種證據,再把對應機制接到真實部署架構,才有條件討論自動化到哪一步最合適。

資料來源與素材說明

官方文件核對日:2026 年 11 月 9 日。程式、合成版本與故障情境為原創教學;配圖是概念示意,非真實 production 部署畫面。本篇沒有宣稱完成雲端核准、正式站部署、流量灰度或資料庫回復測試。

內容提供:TARAISG。本文由 AI 協助整理與查核;專題編輯為天地人 AI 編輯計畫的策展角色,未宣稱經具名人工或專家審核。

AI 生成內容

本文由 TARAISG(TIANDIREN AI SOLUTION GROUP)使用 AI 模型產生正文、整理來源並設計實務工具。方法依據與限制列於文末;案例為明確標示的教學假設。未有具名紀錄時,不宣稱經人工或專家審核。

查看內容製作與更正說明

立即領!558元學習投資折抵金

能力投資季。立即領取 558 元學習金!全站線上課立即折抵。只需填寫 Email,即可輕鬆獲得,先領起來,不要錯過!

立即領!559元學習投資折抵金

能力投資季。立即領取 559 元學習金!全站線上課立即折抵。只需填寫 Email,即可輕鬆獲得,先領起來,不要錯過!

立即領!579 元學習金

學習,看見新可能。 10/14 前領取 579 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!599 元學習金

學習,帶來新可能。 09/09 前領取 558 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!558 元學習金

學習,發現新大陸。 8/29 前領取 558 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!559 元學習金

學習,連結新亮點。 8/14 前領取 559 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!555 元學習金

學習,發現更多視角。 6/14 前領取 555 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!556 元學習金

學習,累積無限可能。 5/29 前領取 556 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!557 元學習金

學習,讓我們發現未曾想像的可能!5/14 前領取 557 元折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

立即領!579 元折抵金

知識就是力量,專業成就未來!3/18 前領取 579 元課程折抵金,解鎖數百堂高品質線上課程,提升職場競爭力與專業技能。只需填寫Email,即可輕鬆獲得,投資自己從現在開始!

年終學習金

年終之餘用學習投資自己!填入 Email ,立即領取 588 元年終學習金!數百堂線上課程立即折抵,先領取收藏起來!