上一篇使用 CloudFormation 管理環境設定,透過 Change Set 確認更新會影響哪些資源。
但應用程式成功部署,不代表使用者就能正常操作,容器可能順利啟動,卻在建立訂單時發生錯誤;健康檢查正常,也可能只是因為沒有測到真正出問題的功能。
今天要討論的主題是:新版本如何接手流量,以及發現問題後,能不能安全退回舊版本。
CI(Continuous Integration,持續整合) 透過自動建置與測試,提早發現程式碼整合問題。
CD(Continuous Delivery,持續交付) 則讓通過驗證的版本,能透過一致流程部署,正式上線前仍可保留人工核准。
在 AWS 上,可以使用 CodePipeline 串接流程,由 CodeBuild 執行建置與測試,再交給 ECS 等平台部署。
測試與正式環境應使用同一份已驗證的部署產物,例如固定容器映像檔的 Digest(內容識別值),避免正式部署時重新建置,產生和測試時不同的內容。
流程自動化後,仍要決定新舊版本如何交替、多少流量先交給新版,以及什麼情況應該停止或回復。
Rolling Deployment(滾動部署) 會逐批替換應用程式,例如先啟動部分新版,確認健康後再停止部分舊版,持續到替換完成。
過程中新舊版本會同時存在,因此 API、Session(工作階段)與資料格式必須相容。
以 ECS 為例,可以透過以下設定控制替換過程:
| 設定 | 用途 |
|---|---|
minimumHealthyPercent |
部署期間至少維持多少比例的健康任務 |
maximumPercent |
部署期間允許的任務數量上限 |
假設 Desired Count 為 4,兩者分別設為 100% 與 200%,就允許先增加新版任務,總數最高達 8 個,再移除舊版;底層仍需要足夠的運算容量與子網路 IP。
滾動部署適合一般常駐服務,但退版時通常也需要重新啟動舊版、分批替換,速度會受到啟動時間與健康檢查影響。
分批替換容器,不等於精準控制新版收到的流量比例 ,如果需要讓新版先接收特定比例的請求,就要進一步設計流量分配。
以下為示意圖:
Blue/Green Deployment(藍綠部署) 會保留舊版 Blue,另外準備新版 Green,驗證後再移轉正式流量。
| 階段 | Blue:舊版 | Green:新版 |
|---|---|---|
| 準備新版 | 處理正式流量 | 啟動並接受測試 |
| 移轉流量 | 逐步減少流量或保留待命 | 接手正式流量 |
| 觀察完成 | 移除或縮減 | 持續提供服務 |
藍綠部署可以一次切換流量,也可以搭配 Canary 或 Linear 逐步移轉,具體方式取決於部署工具與設定。
只要舊版仍在運行、資料格式相容,就能透過切回流量縮短回復時間,不過需要承擔的是新舊版本並存的資源用量,以及流量切換與連線排空的管理。
這兩套環境可以只涵蓋應用程式層,如果共用資料庫,新版寫入的資料也會影響舊版,切回流量不會復原資料。
另外,快速切回的能力有時間限制,舊版任務在觀察期結束後被移除,若才發現問題,就需要重新部署舊版,不能再假設它隨時可以接手。
以下為示意圖:
如果不希望一次讓全部流量接觸新版,可以採用 Canary(金絲雀發布) 或 Linear(線性發布)。
以下比例只是示意:
| 方式 | 新版流量分配 | 驗證方式 |
|---|---|---|
| Canary | 先 10%,確認後再到 100% | 先以少量真實流量驗證,再移轉剩餘流量 |
| Linear | 20% → 40% → 60% → 80% → 100% | 每次增加固定比例,分段觀察 |
藍綠部署描述新舊版本如何並存;Canary 與 Linear 描述流量如何移轉,兩者可以搭配使用,Amazon ECS 使用 ECS Deployment Controller(部署控制器)時,支援 Rolling、Blue/Green、Canary 與 Linear,實際可用功能仍需配合服務與流量路由設定。
漸進式發布需要能辨識新版的錯誤,如果只檢查容器有沒有啟動,就算只放 10% 流量,也可能持續讓使用者遇到業務問題。
同樣地,流量太少時,不能只因為觀察了幾分鐘、沒有告警,就認定新版安全,還要確認請求樣本與關鍵操作是否足夠。
以下為示意圖:
以下是一個假設案例:訂單 API 執行在 ECS,透過 Application Load Balancer(ALB,應用程式負載平衡器)接收請求,平常維持 4 個任務,團隊能接受部署期間多跑一組任務,希望先用少量真實流量驗證新版,通過後即可接受全量切換,並保留舊版以便回復。
在這些條件下,可優先選擇 Canary 發布,由 ECS 配合 ALB,將流量分配到新舊版本各自的目標群組。
滾動部署沒有直接提供本案例需要的流量比例控制,一次切換全部流量則會讓新版立即影響所有請求。
Canary 與 Linear 都能從少量流量開始,這次選 Canary 是因為初步驗證通過後即可全量切換,不需要逐級增加流量,若擔心新版隨負載增加出現連線池、資料庫或其他資源瓶頸,希望逐級提高流量並觀察,就優先評估 Linear。
本案例先讓新版接收 10% 流量,設定 10 分鐘的 Canary Bake Time(金絲雀觀察時間),並檢查:
| 檢查項目 | 判斷重點 |
|---|---|
| 訂單建立成功率 | 以符合業務條件的請求為基礎,確認新版是否比舊版惡化 |
| HTTP 5xx 與逾時比例 | 比較同時段新舊版本,辨識新版增加的錯誤 |
| P95 回應時間 | 約 95% 的請求回應時間不超過此值;比較新舊版本,確認延遲是否惡化 |
| 樣本量與功能涵蓋 | 確認主要下單流程已被執行,不能只看成功次數 |
10% 與 10 分鐘是教學假設,不是通用門檻,正式上線前應依平常表現與服務目標訂出可接受的差異;新舊版本一起變差時,即使兩者表現相近,也不能放行。
即使 Canary 通過,切換至 100% 流量後仍要觀察完整負載下的表現,ECS 的 Deployment Bake Time(部署觀察時間) 可以在全量切換後保留舊版,讓團隊繼續檢查連線池、資料庫負載與錯誤率,再結束部署。
這個選擇需要接受額外容量與驗證流程的管理責任,如果只是低風險的內部 API,也能接受逐批退版,滾動部署就會更直接。
健康檢查與業務驗證需要分開設計:
CloudWatch Alarm 可以監看錯誤率與延遲,但訂單成功率等業務指標,需要應用程式先提供,指標也應能區分新舊版本,避免新版只接收少量流量時,問題被整體平均值掩蓋。
部署前還要確認舊版映像檔、設定與必要權限仍然可用,若只保留版本號,卻無法重新啟動舊版,退版計畫就無法執行。
即使流量已切回,既有長連線或背景工作仍可能繼續執行新版邏輯;已寄出的通知、已扣除的款項與已寫入的錯誤資料,也需要另外做修復。
假設舊版使用資料庫欄位 address,新版改用 shipping_address,如果部署新版時立即刪除舊欄位,即使程式退回舊版,也會因找不到欄位而失敗。
這類變更可以參考以下做法:採用 Expand and Contract(先擴充、後收斂)
shipping_address,暫時保留 address。這會增加過渡期的開發與驗證工作,卻能保留退版空間,相同原則也適用於 API 與事件格式,不能假設所有使用者或消費者都已同步更新。
安全退版的重要前提,是舊程式仍能處理目前的資料與訊息,且所需的執行環境與相依服務仍然可用 ,將資料庫還原到部署前,也可能遺失上線後的正常交易,不能當成日常退版的固定做法。
部署流程需要依靠指標判斷新版是否正常,但 CPU 正常、健康檢查通過,使用者仍可能覺得服務很慢。
下一篇會從 Metrics(指標)、Logs(日誌)與 Traces(追蹤)出發,看看如何從使用者的症狀追到真正出問題的服務。