剛用 Kubernetes(K8s)部署應用時,我直接用 kubectl run 創建 Pod,結果一次誤操作刪除了 Pod,服務直接中斷;後來升級應用時,手動刪除舊 Pod 再創建新 Pod,導致服務短暫不可用。直到用上 Deployment,這些問題都迎刃而解——它能自動維護 Pod 數量、支持滾動更新、一鍵回滾版本,成為 K8s 中最常用的控制器。理解 Deployment 的核心原理,不僅能靈活部署應用,還能搞懂 K8s 控制器的設計思想。

一、核心認知:Deployment 是什麼?

Deployment 是 K8s 中用於管理無狀態應用的控制器,它不直接創建 Pod,而是通過管理 ReplicaSet(副本集)來間接管理 Pod。簡單説,Deployment 是 ReplicaSet 的“上層管理者”,負責定義應用的期望狀態(如副本數、鏡像版本),而 ReplicaSet 負責執行具體的 Pod 創建、刪除操作,確保實際狀態與期望狀態一致。

Deployment 的核心價值:

  1. 自動擴縮容:確保指定數量的 Pod 始終運行;
  2. 滾動更新:升級應用時不中斷服務,支持灰度發佈;
  3. 版本回滾:升級失敗時快速回滾到上一個穩定版本;
  4. 自愈能力:Pod 因節點故障或異常退出時,自動重建新 Pod。

舉個通俗的例子:Deployment 就像餐廳經理,負責制定“保持 3 個服務員在崗”的規則(期望狀態);ReplicaSet 像領班,負責盯着實際到崗人數,有人請假就立刻招人替補,確保始終符合經理的要求。

二、核心原理:Deployment → ReplicaSet → Pod 的關係

Deployment 的工作流程本質是“三層結構”:Deployment 管理 ReplicaSet,ReplicaSet 管理 Pod,每層各司其職,確保流程穩定。

1. 三層結構關係

  • Deployment:定義頂層規則,如 replicas: 3(期望 3 個 Pod)、image: nginx:1.21(鏡像版本)、更新策略等;
  • ReplicaSet:由 Deployment 自動創建,每個 Deployment 版本對應一個 ReplicaSet(通過 revision 標識),核心職責是維持 Pod 副本數;
  • Pod:由 ReplicaSet 按模板(PodTemplate)創建,是實際運行應用的最小單元。

當你創建一個 Deployment 時,K8s 會自動完成:

  1. 創建 Deployment 對象,記錄期望狀態;
  2. 基於 Deployment 配置,創建一個 ReplicaSet;
  3. ReplicaSet 根據 replicas 數量,創建對應數量的 Pod。

2. 關鍵字段解析(Deployment YAML 示例)

以下是一個標準的 Deployment YAML 文件,核心字段對應核心功能:

apiVersion: apps/v1  # API 版本(必須為 apps/v1)
kind: Deployment     # 資源類型為 Deployment
metadata:
  name: nginx-deploy  # Deployment 名稱
  labels:
    app: nginx        # 自定義標籤(用於篩選)
spec:
  replicas: 3         # 期望 Pod 副本數(核心字段)
  selector:
    matchLabels:
      app: nginx      # 匹配 Pod 的標籤(必須與 PodTemplate 一致)
  strategy:
    type: RollingUpdate  # 更新策略:滾動更新(默認)
    rollingUpdate:
      maxSurge: 1        # 滾動更新時,最多可額外創建 1 個 Pod(避免資源耗盡)
      maxUnavailable: 0  # 滾動更新時,最多不可用的 Pod 數(0 表示不允許中斷服務)
  template:
    # Pod 模板(定義 Pod 的配置)
    metadata:
      labels:
        app: nginx  # Pod 標籤(必須與 selector.matchLabels 一致)
    spec:
      containers:
      - name: nginx
        image: nginx:1.21  # 容器鏡像(更新應用時修改此處)
        ports:
        - containerPort: 80  # 容器暴露端口

應用這個 YAML:

kubectl apply -f nginx-deploy.yaml

查看創建的資源:

# 查看 Deployment
kubectl get deploy
# 查看 ReplicaSet(名稱格式:Deployment名稱-隨機字符串)
kubectl get rs
# 查看 Pod(名稱格式:ReplicaSet名稱-隨機字符串)
kubectl get pods

三、核心功能實戰:滾動更新與回滾

Deployment 最實用的功能是滾動更新和版本回滾,這也是它比直接用 ReplicaSet 更靈活的關鍵。

1. 滾動更新:無停機升級應用

當需要升級應用版本(如從 nginx:1.21 升級到 nginx:1.23)時,滾動更新會逐步替換舊 Pod,確保服務不中斷。

操作步驟:
  1. 修改 Deployment 的鏡像版本(兩種方式):
  • 直接編輯 YAML:將 image: nginx:1.21 改為 image: nginx:1.23,重新應用:
kubectl apply -f nginx-deploy.yaml
  • 用命令行快速修改:
kubectl set image deployment/nginx-deploy nginx=nginx:1.23
  1. 查看更新過程:
kubectl rollout status deployment/nginx-deploy
滾動更新原理:

根據 strategy.rollingUpdate 配置(maxSurge:1maxUnavailable:0),更新流程為:

  1. 先創建 1 個新 Pod(基於 nginx:1.23 鏡像);
  2. 等待新 Pod 就緒(Ready 狀態);
  3. 刪除 1 箇舊 Pod(基於 nginx:1.21 鏡像);
  4. 重複步驟 1-3,直到所有舊 Pod 被替換為新 Pod。

整個過程中,可用 Pod 數量始終保持 3 個(maxUnavailable:0),服務完全不中斷。

2. 版本回滾:升級失敗時快速恢復

如果升級後發現新鏡像有 bug,可一鍵回滾到上一個穩定版本。

操作步驟:
  1. 查看 Deployment 的版本歷史(revision):
kubectl rollout history deployment/nginx-deploy
# 查看某個版本的詳細信息(如 revision=1)
kubectl rollout history deployment/nginx-deploy --revision=1
  1. 回滾到上一個版本(或指定版本):
# 回滾到上一個版本
kubectl rollout undo deployment/nginx-deploy
# 回滾到指定版本(如 revision=1)
kubectl rollout undo deployment/nginx-deploy --to-revision=1
  1. 驗證回滾結果:
# 查看 Pod 的鏡像版本是否恢復
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
回滾原理:

Deployment 的每個版本對應一個 ReplicaSet,回滾本質是:

  1. 激活上一個版本的 ReplicaSet(修改其 replicas 數量為期望數);
  2. 將當前版本的 ReplicaSet 的 replicas 數量改為 0,舊 Pod 會被逐步刪除;
  3. 上一個版本的 ReplicaSet 重新創建對應數量的 Pod,恢復到之前的穩定狀態。

3. 暫停與恢復更新(高級用法)

如果需要在更新過程中執行額外操作(如手動測試),可暫停更新,完成後再恢復:

# 暫停更新
kubectl rollout pause deployment/nginx-deploy

# 執行額外操作(如查看新 Pod 日誌、手動測試接口)
kubectl logs <new-pod-name>
curl <pod-ip>:80

# 恢復更新
kubectl rollout resume deployment/nginx-deploy

四、進階特性:擴縮容與自愈能力

1. 手動擴縮容:調整 Pod 數量

根據業務流量變化,可手動調整 Pod 副本數:

# 擴縮容到 5 個 Pod
kubectl scale deployment/nginx-deploy --replicas=5

# 驗證結果
kubectl get pods

也可以直接編輯 Deployment 的 replicas 字段,重新應用 YAML 文件,效果一致。

2. 自愈能力:自動重建異常 Pod

Deployment 的自愈能力由 ReplicaSet 實現:當 Pod 因節點故障、容器崩潰等原因異常退出時,ReplicaSet 會檢測到實際 Pod 數量小於期望數,自動在健康的節點上創建新 Pod。

測試自愈能力:

# 手動刪除一個 Pod
kubectl delete pod <pod-name>

# 查看是否自動重建新 Pod(幾秒內會出現新的 Pod)
kubectl get pods --watch

輸出示例(刪除後立即創建新 Pod):

nginx-deploy-7f96f7d6c4-2xqzk   1/1     Running   0          10s
nginx-deploy-7f96f7d6c4-2xqzk   1/1     Terminating   0          15s
nginx-deploy-7f96f7d6c4-5m7p8   0/1     Pending       0          0s
nginx-deploy-7f96f7d6c4-5m7p8   0/1     ContainerCreating   0          1s
nginx-deploy-7f96f7d6c4-5m7p8   1/1     Running             0          3s

五、避坑指南:Deployment 使用常見問題

1. 標籤不匹配導致 Pod 無法創建

Deployment 的 spec.selector.matchLabels 必須與 spec.template.metadata.labels 完全一致,否則 ReplicaSet 無法匹配 Pod,會一直處於“Pending”狀態。

# 錯誤示例:標籤不一致
spec:
  selector:
    matchLabels:
      app: nginx  # 選擇 app=nginx 的 Pod
  template:
    metadata:
      labels:
        app: web  # Pod 標籤為 app=web,不匹配

2. 滾動更新卡住(Pod 無法就緒)

如果新 Pod 因鏡像拉取失敗、配置錯誤等原因無法進入 Ready 狀態,滾動更新會卡住(一直等待新 Pod 就緒)。解決方法:

# 查看 Pod 日誌,排查故障原因
kubectl logs <pending-pod-name>

# 如需終止更新,可回滾到上一個版本
kubectl rollout undo deployment/nginx-deploy

3. 忽略鏡像拉取策略導致更新不生效

默認情況下,K8s 會使用 imagePullPolicy: IfNotPresent(本地有鏡像則不重新拉取)。如果鏡像標籤不變(如使用 latest 標籤),修改鏡像後更新可能不生效。解決方法:

  • 避免使用 latest 標籤,改用具體版本號(如 nginx:1.23);
  • 手動設置 imagePullPolicy: Always(每次都重新拉取鏡像):
spec:
  template:
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: Always  # 每次都拉取鏡像

4. 擴縮容時資源不足

如果集羣節點的 CPU/內存不足,擴縮容時新 Pod 會一直處於 Pending 狀態。解決方法:

  • 檢查節點資源使用情況:kubectl describe nodes
  • 調整 Deployment 的資源限制(resources.limits),或添加新節點。

5. 誤刪 Deployment 導致服務中斷

刪除 Deployment 時,會自動刪除其管理的 ReplicaSet 和 Pod,導致服務中斷。如果需要保留 Pod,可先縮放 ReplicaSet 到 0,再刪除 Deployment:

# 查看 Deployment 對應的 ReplicaSet
kubectl get rs

# 縮放 ReplicaSet 到 0(保留 ReplicaSet,刪除 Pod)
kubectl scale rs <rs-name> --replicas=0

# 或直接保留 Pod(修改 ReplicaSet 的 selector,與 Pod 標籤解綁)
kubectl patch rs <rs-name> -p '{"spec":{"selector":{"matchLabels":{"app":"nginx-temp"}}}}'

總結

Deployment 是 K8s 管理無狀態應用的核心控制器,核心邏輯是“通過 ReplicaSet 維持 Pod 期望狀態”,核心價值是“無停機更新、版本回滾、自愈擴縮容”。理解它的三層結構(Deployment → ReplicaSet → Pod),就能明白其各項功能的實現原理。

實戰中,建議:

  1. 所有無狀態應用(如 Web 服務、API 接口)都用 Deployment 部署,避免直接創建 Pod;
  2. 配置合理的滾動更新策略(maxSurgemaxUnavailable),確保服務不中斷;
  3. 鏡像使用具體版本號,避免 latest 標籤導致更新異常;
  4. 定期查看 Deployment 狀態和版本歷史,便於故障時快速回滾。

掌握 Deployment 後,你會發現 K8s 部署應用變得靈活又可靠,無論是日常版本升級、流量峯值擴縮容,還是故障恢復,都能高效應對。這也是從“會用 K8s”到“用好 K8s”的關鍵一步。