在 Kubernetes(K8s)集羣中部署應用時,最頭疼的就是版本更新——直接重啓服務會導致業務中斷,影響用户體驗。而 K8s 自帶的滾動更新(Rolling Update)功能完美解決了這個問題:它能逐步替換舊版本 Pod,在更新過程中保持部分實例可用,實現零停機部署;一旦更新出現問題,還能快速回滾到穩定版本,極大降低發佈風險。這篇就分享滾動更新與回滾的核心配置和實戰技巧,幫你安全高效地完成應用迭代。

一、核心認知:滾動更新的工作原理

滾動更新是 Deployment 控制器的默認更新策略,核心邏輯是“逐步替換、灰度發佈”:

  1. 按照配置的比例,先創建少量新版本 Pod;
  2. 等待新版本 Pod 就緒(Ready 狀態)後,銷燬同等數量的舊版本 Pod;
  3. 重複上述步驟,直到所有舊版本 Pod 被替換為新版本;
  4. 整個過程中,服務始終有可用實例,用户無感知。

關鍵參數(控制更新節奏):

  • maxSurge:更新過程中允許超出期望副本數的最大 Pod 數量(可設為整數或百分比,默認 25%);
  • maxUnavailable:更新過程中允許不可用的最大 Pod 數量(可設為整數或百分比,默認 25%)。

簡單説,這兩個參數就像“更新閥門”:maxSurge 控制“最多多啓動多少新 Pod”,maxUnavailable 控制“最多允許多少舊 Pod 不可用”,合理配置能平衡更新速度和服務穩定性。

二、實戰:滾動更新配置與操作

以一個 Nginx 應用為例,演示如何配置滾動更新並執行版本升級。

1. 編寫 Deployment 配置(含滾動更新策略)

創建 nginx-deployment.yaml 文件,明確配置滾動更新參數:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 4  # 期望副本數(4 個實例,保證更新時高可用)
  strategy:
    type: RollingUpdate  # 滾動更新策略(默認,可省略)
    rollingUpdate:
      maxSurge: 1  # 最多多啓動 1 個 Pod(避免資源佔用過高)
      maxUnavailable: 0  # 不允許任何 Pod 不可用(優先保證服務穩定)
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.21-alpine  # 初始版本(舊版本)
        ports:
        - containerPort: 80
        readinessProbe:  # 就緒探針(關鍵!確保 Pod 真正可用才接收流量)
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5  # 啓動後 5 秒開始探測
          periodSeconds: 3  # 每 3 秒探測一次

2. 部署初始版本

# 創建 Deployment
kubectl apply -f nginx-deployment.yaml

# 查看部署狀態(確保 4 個 Pod 均為 Running)
kubectl get pods -l app=nginx
# 輸出示例:4 個 nginx:1.21-alpine 版本的 Pod 運行中

3. 執行滾動更新(升級版本)

通過修改鏡像版本觸發滾動更新,有兩種方式:

方式 1:編輯 Deployment 配置(推薦生產環境)
# 編輯配置,將鏡像改為 nginx:1.23-alpine(新版本)
kubectl edit deployment nginx-deploy

在編輯界面找到 image: nginx:1.21-alpine,改為 image: nginx:1.23-alpine,保存退出。

方式 2:用 set image 命令(快速測試)
# 直接指定新鏡像版本
kubectl set image deployment/nginx-deploy nginx=nginx:1.23-alpine

4. 觀察滾動更新過程

# 實時查看 Pod 狀態變化
kubectl get pods -l app=nginx -w

觀察輸出會發現:

  1. 先啓動 1 個 nginx:1.23-alpine 新版本 Pod(符合 maxSurge:1);
  2. 新版本 Pod 就緒後,銷燬 1 箇舊版本 Pod;
  3. 重複步驟 1-2,直到 4 個 Pod 全部替換為新版本;
  4. 整個過程中,始終有 4 個 Pod 可用(maxUnavailable:0 生效)。

5. 驗證更新結果

# 查看 Deployment 狀態(確認更新完成)
kubectl rollout status deployment/nginx-deploy
# 輸出:deployment "nginx-deploy" successfully rolled out

# 驗證所有 Pod 均為新版本
kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.spec.containers[0].image}{"\n"}{end}'
# 輸出均為 nginx:1.23-alpine

三、實戰:更新失敗後的快速回滾

如果新版本存在 Bug(如鏡像拉取失敗、服務異常),需要立即回滾到上一個穩定版本。

1. 模擬更新失敗

故意使用一個不存在的鏡像版本,觸發更新失敗:

kubectl set image deployment/nginx-deploy nginx=nginx:invalid-version

觀察 Pod 狀態,會發現新 Pod 處於 ImagePullBackOff 狀態,舊 Pod 被逐步銷燬但新 Pod 無法就緒,服務面臨不可用風險。

2. 查看更新歷史

# 查看 Deployment 滾動更新歷史
kubectl rollout history deployment/nginx-deploy
# 輸出示例:
# deployments "nginx-deploy"
# REVISION  CHANGE-CAUSE
# 1         kubectl apply --filename=nginx-deployment.yaml
# 2         kubectl set image deployment/nginx-deploy nginx=nginx:1.23-alpine
# 3         kubectl set image deployment/nginx-deploy nginx=nginx:invalid-version

3. 回滾到上一個穩定版本(REVISION 2)

# 回滾到上一版本(快速回滾)
kubectl rollout undo deployment/nginx-deploy

# 或指定回滾到某個具體版本(如 REVISION 1)
# kubectl rollout undo deployment/nginx-deploy --to-revision=1

4. 驗證回滾結果

# 查看回滾狀態
kubectl rollout status deployment/nginx-deploy

# 驗證 Pod 鏡像已回滾到穩定版本
kubectl get pods -l app=nginx -o jsonpath='{range .items[*]}{.spec.containers[0].image}{"\n"}{end}'
# 輸出均為 nginx:1.23-alpine(穩定版本)

四、關鍵優化:零停機部署的核心技巧

1. 必須配置就緒探針(readinessProbe)

這是零停機的核心保障!如果沒有就緒探針,K8s 會認為 Pod 啓動後就可用,但此時服務可能還在初始化(如加載配置),直接接收流量會導致請求失敗。配置就緒探針後,只有探測成功的 Pod 才會被納入服務訪問列表。

2. 合理配置 maxSurge 和 maxUnavailable

  • 追求穩定性(如核心服務):maxSurge: 10%maxUnavailable: 0,確保更新過程中無服務中斷;
  • 追求更新速度(如非核心服務):maxSurge: 50%maxUnavailable: 20%,加快更新節奏;
  • 資源緊張場景:降低 maxSurge(如 1),避免更新時佔用過多 CPU/內存。

3. 版本標籤化(避免使用 latest 鏡像)

永遠不要使用 nginx:latest 這類標籤,因為 latest 是動態的,更新後無法回滾到確切版本。建議使用固定版本標籤(如 nginx:1.23.1-alpine),確保更新和回滾的可追溯性。

4. 小步迭代,控制副本數

  • 副本數建議 ≥3,更新時能保證足夠的可用實例;
  • 重大版本更新可分階段進行:先更新 10% 副本觀察,再逐步擴大範圍。

五、避坑指南

1. 更新卡住(一直處於 Progressing 狀態)

  • 原因:新 Pod 無法就緒(如就緒探針配置錯誤、鏡像拉取失敗);
  • 解決:
  1. 查看 Pod 日誌:kubectl logs <pod-name>
  2. 描述 Pod 排查問題:kubectl describe pod <pod-name>
  3. 修復問題後重新觸發更新,或直接回滾。

2. 回滾後服務仍異常

  • 原因:回滾時舊 Pod 未徹底銷燬,或配置殘留;
  • 解決:
  1. 強制刪除異常 Pod:kubectl delete pod <pod-name> --force
  2. 驗證 Deployment 配置:kubectl get deployment nginx-deploy -o yaml,確保鏡像版本正確。

3. 資源不足導致更新失敗

  • 原因:maxSurge 配置過大,更新時啓動的新 Pod 超出集羣資源上限;
  • 解決:降低 maxSurge 數值,或擴容集羣資源。

總結

K8s 滾動更新與回滾是實現零停機部署的核心能力,核心要點可概括為:

  1. 配置就緒探針,確保 Pod 真正可用;
  2. 合理設置 maxSurgemaxUnavailable,平衡穩定性和更新速度;
  3. 使用固定版本鏡像,保證更新和回滾的可追溯性;
  4. 出現問題時,通過 kubectl rollout undo 快速回滾,降低風險。

這套方案適用於絕大多數微服務的版本迭代,無論是小版本 bug 修復,還是重大功能升級,都能在不影響用户體驗的前提下完成部署。掌握這些技巧後,你可以放心地進行頻繁的版本發佈,真正實現 DevOps 所倡導的“持續部署”理念。