結論先講
Rolling Update 是 80% 場景的正解。 K8s 預設就是 Rolling Update,設定好 maxSurge 和 maxUnavailable 就能用。Blue-Green 適合「一秒都不能錯」的金融場景,但你要付雙倍的機器成本。Canary 適合面對大量用戶的 toC 產品,先讓 5% 流量試水溫。不確定選哪個?先用 Rolling Update,痛了再換。
三種策略一覽
Rolling Update:
v1 v1 v1 v1 ← 4 個 Pod
v2 v1 v1 v1 ← 逐一替換
v2 v2 v1 v1
v2 v2 v2 v1
v2 v2 v2 v2 ← 全部更新完成
Blue-Green:
[v1 v1 v1 v1] ← Blue(正在服務)
[v2 v2 v2 v2] ← Green(準備好了)
切換 → Green 開始服務,Blue 待命
確認沒問題 → 關掉 Blue
Canary:
v1 v1 v1 v1 v1 v1 v1 v1 v1 v1 ← 100% 流量
v2 v1 v1 v1 v1 v1 v1 v1 v1 v1 ← 10% 流量到 v2
觀察 metrics...
v2 v2 v2 v1 v1 v1 v1 v1 v1 v1 ← 30% 流量到 v2
觀察 metrics...
v2 v2 v2 v2 v2 v2 v2 v2 v2 v2 ← 100% 流量到 v2
Rolling Update
K8s 設定
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 最多多開 1 個 Pod
maxUnavailable: 1 # 最多 1 個 Pod 不可用
template:
spec:
containers:
- name: order-service
image: order-service:v2
readinessProbe: # 關鍵:新 Pod 準備好才接流量
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 3優缺點
| 優點 | 缺點 |
|---|---|
| K8s 預設,零額外設定 | 回滾需要時間(逐一替換回來) |
| 不需要雙倍資源 | 部署過程中 v1 和 v2 同時存在 |
| 對 stateless 服務完美適用 | DB schema 變更要特別小心 |
v1 和 v2 同時存在的問題
部署過程中:
Pod 1: v2(新 API 回傳多了一個欄位)
Pod 2: v1(舊 API 沒有那個欄位)
用戶 A 的請求打到 v2 → 拿到新欄位 → 正常
用戶 A 下一個請求打到 v1 → 沒有新欄位 → 前端爆了?
解法:
API 變更必須向後相容(backward compatible)
- 新增欄位:OK(v1 client 忽略新欄位)
- 刪除欄位:先標 deprecated → 下下個版本才移除
- 改欄位格式:開新欄位,保留舊欄位
Blue-Green Deployment
Nginx 切換
# 初始狀態:流量到 Blue
upstream order-service {
server blue-order:8080;
}
# 部署 Green 環境,測試通過後:
upstream order-service {
server green-order:8080; # 切到 Green
}
# reload nginx → 流量瞬間切換,零停機K8s 做法
# Blue:目前在服務的
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
version: blue # ← 指向 blue deployment
# 部署 Green deployment,測試通過後:
# kubectl patch service order-service -p '{"spec":{"selector":{"version":"green"}}}'
# 一行指令切換,回滾也是一行優缺點
| 優點 | 缺點 |
|---|---|
| 切換瞬間完成 | 需要雙倍資源(兩套環境同時跑) |
| 回滾一秒完成(切回去) | 資料庫 migration 要兩個版本都相容 |
| 可以在 Green 上充分測試 | 成本高 |
Blue-Green 最適合:金融、醫療、政府等對停機零容忍的場景。
Canary Deployment
用 Nginx 做流量分配
upstream order-service {
server order-v1:8080 weight=9; # 90% 流量
server order-v2:8080 weight=1; # 10% 流量
}
# 觀察 10 分鐘,error rate 沒上升 → 調整為 50/50
# 再觀察 → 調整為 0/100用 Istio 做更精細的控制
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
spec:
http:
- route:
- destination:
host: order-service
subset: v1
weight: 90
- destination:
host: order-service
subset: v2
weight: 10Istio 還能做更進階的:只讓內部員工的流量打到 v2(用 header match),或只讓特定地區的用戶打到 v2。
自動化 Canary:Flagger / Argo Rollouts
手動調流量太累,用工具自動化:
1. 部署 v2,初始流量 5%
2. 每 5 分鐘檢查 metrics(error rate、latency)
3. 如果 metrics 正常 → 流量 +10%
4. 如果 metrics 異常 → 自動回滾到 v1
5. 到 100% → 部署完成
部署時跑壓測:用 k6 驗證
部署過程中跑壓測,確認服務不會掛:
// k6-deploy-test.js
import http from 'k6/http';
import { check } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 50 }, // 部署前:穩定 50 用戶
{ duration: '5m', target: 50 }, // 部署中:維持 50 用戶觀察
{ duration: '1m', target: 0 }, // 收尾
],
thresholds: {
http_req_failed: ['rate<0.01'], // 錯誤率 < 1%
http_req_duration: ['p95<500'], // P95 < 500ms
},
};
export default function () {
const res = http.get('https://api.example.com/orders');
check(res, { 'status 200': (r) => r.status === 200 });
}如同 第 41 篇 和 第 42 篇 討論的容器化基礎,部署策略是建立在容器之上的。
怎麼選
| 條件 | Rolling Update | Blue-Green | Canary |
|---|---|---|---|
| 團隊經驗 | 初階 | 中階 | 進階 |
| 額外成本 | 低(+25%) | 高(+100%) | 中(+10-30%) |
| 回滾速度 | 分鐘級 | 秒級 | 秒級 |
| 部署風險 | 中 | 低 | 最低 |
| 適用場景 | 內部工具、一般 API | 金融、醫療 | toC 高流量 |
我的建議:從 Rolling Update 開始。 等你遇到「部署後 5 分鐘發現 bug,回滾來不及」的痛,再考慮 Canary。等你遇到「客戶合約要求 99.99% uptime」的壓力,再上 Blue-Green。
下一篇
微服務安全 — 部署搞定了,但如果服務之間的通訊沒有認證,任何人都能偽裝成 Payment Service 去呼叫 Order Service。mTLS、JWT、API Key 怎麼選?
本系列文章
完整 68 篇目錄見 系列首頁
← 上一篇:CD:每個 Service 獨立 Pipeline → 下一篇:微服務安全(一):服務間認證 mTLS vs JWT vs API Key