剛用 Kubernetes(K8s)部署應用時,我直接用 kubectl run 創建 Pod,結果一次誤操作刪除了 Pod,服務直接中斷;後來升級應用時,手動刪除舊 Pod 再創建新 Pod,導致服務短暫不可用。直到用上 Deployment,這些問題都迎刃而解——它能自動維護 Pod 數量、支持滾動更新、一鍵回滾版本,成為 K8s 中最常用的控制器。理解 Deployment 的核心原理,不僅能靈活部署應用,還能搞懂 K8s 控制器的設計思想。
一、核心認知:Deployment 是什麼?
Deployment 是 K8s 中用於管理無狀態應用的控制器,它不直接創建 Pod,而是通過管理 ReplicaSet(副本集)來間接管理 Pod。簡單説,Deployment 是 ReplicaSet 的“上層管理者”,負責定義應用的期望狀態(如副本數、鏡像版本),而 ReplicaSet 負責執行具體的 Pod 創建、刪除操作,確保實際狀態與期望狀態一致。
Deployment 的核心價值:
- 自動擴縮容:確保指定數量的 Pod 始終運行;
- 滾動更新:升級應用時不中斷服務,支持灰度發佈;
- 版本回滾:升級失敗時快速回滾到上一個穩定版本;
- 自愈能力: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 會自動完成:
- 創建 Deployment 對象,記錄期望狀態;
- 基於 Deployment 配置,創建一個 ReplicaSet;
- 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,確保服務不中斷。
操作步驟:
- 修改 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
- 查看更新過程:
kubectl rollout status deployment/nginx-deploy
滾動更新原理:
根據 strategy.rollingUpdate 配置(maxSurge:1、maxUnavailable:0),更新流程為:
- 先創建 1 個新 Pod(基於 nginx:1.23 鏡像);
- 等待新 Pod 就緒(Ready 狀態);
- 刪除 1 箇舊 Pod(基於 nginx:1.21 鏡像);
- 重複步驟 1-3,直到所有舊 Pod 被替換為新 Pod。
整個過程中,可用 Pod 數量始終保持 3 個(maxUnavailable:0),服務完全不中斷。
2. 版本回滾:升級失敗時快速恢復
如果升級後發現新鏡像有 bug,可一鍵回滾到上一個穩定版本。
操作步驟:
- 查看 Deployment 的版本歷史(
revision):
kubectl rollout history deployment/nginx-deploy
# 查看某個版本的詳細信息(如 revision=1)
kubectl rollout history deployment/nginx-deploy --revision=1
- 回滾到上一個版本(或指定版本):
# 回滾到上一個版本
kubectl rollout undo deployment/nginx-deploy
# 回滾到指定版本(如 revision=1)
kubectl rollout undo deployment/nginx-deploy --to-revision=1
- 驗證回滾結果:
# 查看 Pod 的鏡像版本是否恢復
kubectl get pods -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
回滾原理:
Deployment 的每個版本對應一個 ReplicaSet,回滾本質是:
- 激活上一個版本的 ReplicaSet(修改其
replicas數量為期望數); - 將當前版本的 ReplicaSet 的
replicas數量改為 0,舊 Pod 會被逐步刪除; - 上一個版本的 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),就能明白其各項功能的實現原理。
實戰中,建議:
- 所有無狀態應用(如 Web 服務、API 接口)都用 Deployment 部署,避免直接創建 Pod;
- 配置合理的滾動更新策略(
maxSurge、maxUnavailable),確保服務不中斷; - 鏡像使用具體版本號,避免
latest標籤導致更新異常; - 定期查看 Deployment 狀態和版本歷史,便於故障時快速回滾。
掌握 Deployment 後,你會發現 K8s 部署應用變得靈活又可靠,無論是日常版本升級、流量峯值擴縮容,還是故障恢復,都能高效應對。這也是從“會用 K8s”到“用好 K8s”的關鍵一步。