聊聊發布的那點事,零停機是不是神話?
零停機就是用戶無感知的發布。請求不斷。連接不中斷。服務平穩切換到新版本。重要的是用戶體驗不變。
聽起來好聽,但它不是魔法。它靠方法、流程和反復演練。

一、先聊基本原則
改動要向后兼容。流量要可控。實例要能優雅下線。數據庫變更要可回滾。步驟要自動化并可審計。
二、常見的發布策略與取舍
1. Blue-Green(藍綠)
我會把新版本部署到綠環境。驗證無誤再切流量到綠。回滾只需把流量切回藍。缺點是需要額外資源。
示例:切流量命令和校驗輸出如下。
$ kubectl patch svc myservice -n prod -p '{"spec":{"selector":{"app":"green"}}}'
service/myservice patched$ kubectl get endpoints myservice -n prod -o wide
NAME ENDPOINTS
myservice 10.244.1.12:8080,10.244.2.15:8080這適合能承受雙倍容量的場景。
2. Canary(金絲雀)
把少量真實流量先丟給新版本。觀察指標后逐步放量。我建議把錯誤率和 95% 延遲作為準入門檻。用服務網格能精細控制權重。
示例:把 Canary 配置應用后的反饋。
$ kubectl apply -f virtualservice-canary.yaml -n prod
virtualservice.networking.istio.io/myservice configured金絲雀適合風險較高的功能變更。
3. Rolling Update(滾動升級)
在資源有限時使用它。Kubernetes 按策略替換 Pod。關鍵是 readiness 要做得嚴一點。
更新和觀察命令如下。
$ kubectl set image deployment/myapp mycontainer=myapp:2025-09-01 -n prod
deployment.apps/myapp image updated
$ kubectl rollout status deployment/myapp -n prod
Waiting for rollout to finish: 2 of 3 updated...
deployment "myapp" successfully rolled out滾動時要保證舊實例能處理未完成的請求。
三、Probe 與優雅下線
readiness 決定實例是否能接流量。liveness 決定容器是否需要重啟。preStop 用來給應用清理并排盡連接。
下面是常見的配置片段(示例保留)。
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
lifecycle:
preStransform: translateY(
exec:
command: ["/bin/sh", "-c", "sleep 10"]preStop 常用來關閉監聽、等待連接數降到 0。這樣能避免半條請求在替換時被中斷。
應用配置后,用下面命令部署并查看狀態。
$ kubectl apply -f deployment.yaml -n prod
deployment.apps/myapp configured四、排干連接的操作
下線節點前先把流量排干。Kubernetes 的 drain 可以把 Pod 驅逐并遷移。
命令與示例輸出如下。
$ kubectl drain node-node01 --ignore-daemonsets --delete-local-data
node/node01 cordoned
evicting pod myapp-abcde...
pod/myapp-abcde evicted
node/node01 drained對外部負載均衡器亦同理。先從后端池移出實例。觀察活躍連接為 0 再做維護。
五、數據庫模式變更:分階段、安全為王
數據庫變更最容易翻車。原則是小步快跑,保證可回滾。步驟我常用三段走法:新增字段→雙寫回填→切讀舊字段→刪舊字段。
在線變更工具會把熱表分片拷貝再切換。gh-ost 的示例如下。
$ gh-ost \
--user="ghuser" --password="ghpass" \
--host="db-master" --database="mydb" --table="orders" \
--alter="ADD COLUMN new_flag TINYINT(1) DEFAULT 0" \
--allow-on-master --execute模擬輸出示例:
INFO Migrating table orders
INFO Ghost table created: _orders_gho
INFO Applying row-copy...
INFO Cut-over completed.工具會逐步復制行并最小化鎖定窗口。不要在高峰期做大范圍結構變更。
六、回滾要提前演練
每次發布都要有秒級回滾方案。Kubernetes 支持 rollout undo。
命令和反饋示例:
$ kubectl rollout undo deployment/myapp -n prod
deployment.apps/myapp rolled back
$ kubectl rollout status deployment/myapp -n prod
deployment "myapp" successfully rolled out回滾前要確認目標鏡像、配置和 probe 都存在并可用。回滾也要走健康檢查流程,別跳過驗證。
七、CI/CD 自動化要點(實務)
把發布流程寫成 pipeline。允許人工暫停和審查。關鍵是把發布操作可審計、可回溯。
示例 GitLab CI 片段(占位):
deploy_canary:
stage: deploy
script:
- kubectl apply -f k8s/canary.yaml -n prod
- kubectl rollout status deployment/myapp-canary -n prod
when: manual手動觸發能減少誤發。自動化里也要內置告警觸發回滾的邏輯。
八、驗證與流量測試
上線前做壓力和功能驗證。對比錯誤率、延遲、連接數這三項。
一個常用的壓力測試示例:
$ wrk -t2 -c200 -d30s http://myservice.prod/health
Running 30s test @ http://myservice.prod/health
2 threads and 200 connections
Requests/sec: 12000
Latency 25ms在 Canary 上重復同樣測試。對比指標差異決定是否放量。
九、常見陷阱(一句話一條)
改非兼容字段會出錯。probe 配置太寬松會把未就緒實例拉入流量池。未排干連接就下線會造成錯誤。忘記清理舊指標會誤導后續分析。缺回滾路徑會拉長故障恢復時間。
十、最簡單的安全發布腳本(示例)
這段腳本適合小團隊快速發布并檢查就緒。
#!/bin/bash
set -e
DEPLOY=deployment/myapp
NAMESPACE=prod
NEW_IMAGE=myapp:2025-09-01
echo "更新鏡像..."
kubectl set image $DEPLOY mycontainer=$NEW_IMAGE -n $NAMESPACE
echo "等待 rollout..."
kubectl rollout status $DEPLOY -n $NAMESPACE
echo "檢查 readiness..."
kubectl get pods -l app=myapp -n $NAMESPACE -o jsonpath='{range .items[*]}{.metadata.name} {.status.phase} {.status.containerStatuses[0].ready}{"\n"}{end}'
echo "發布完成"輸出如下:
更新鏡像...
deployment.apps/myapp image updated
等待 rollout...
deployment "myapp" successfully rolled out
myapp-abcde Running true
myapp-fghij Running true
發布完成這只是基礎版。復雜場景要接入流量網格、灰度控制和審計系統。






















