Kubernetes Deployment - 應用程式部署與更新

Deployment 是 Kubernetes 中部署無狀態 (Stateless) 應用程式的標準方式。 它比 ReplicaSet 更高階,提供了 宣告式更新 (Declarative Updates) 的能力,讓我們能輕鬆進行版本升級、回滾與擴展。

Deployment, ReplicaSet 與 Pod 的關係

層級關係如下:

  1. Deployment 管理 ReplicaSet。
  2. ReplicaSet 管理 Pod。

當你更新 Deployment (例如換 image tag),Deployment 會建立一個 新的 ReplicaSet,並逐漸將 Pod 從 舊的 ReplicaSet 遷移過去,這個過程稱為 滾動更新 (Rolling Update)

定義 Deployment

建立 nginx-deployment.yaml

# nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
spec:
  replicas: 3 # 期望的副本數,這裡我們希望有 3 個 Pod 同時運行
  selector:
    matchLabels:
      app: nginx # 用來選擇要管理的 Pod,必須與 template.metadata.labels 匹配
  strategy:
    type: RollingUpdate # 更新策略,預設為 RollingUpdate (滾動更新)
    rollingUpdate:
      maxUnavailable: 1 # 更新過程中,最多允許幾個 Pod 無法服務 (可以是數字或是百分比)
      maxSurge: 1 # 更新過程中,最多允許比期望值 (replicas) 多出幾個 Pod
  template: # Pod 的模板,Deployment 會根據這個模板建立 Pod
    metadata:
      labels:
        app: nginx # Pod 的標籤
    spec:
      containers:
        - name: nginx
          image: nginx:1.14.2 # 容器映像檔,這裡故意先用舊版 1.14.2 作為示範
          ports:
            - containerPort: 80 # 容器暴露的端口

操作 Deployment

建立 Deployment

kubectl apply -f nginx-deployment.yaml

加上 --record 參數可以記錄指令歷程(便於回滾查看),但在新版 kubectl 已棄用,建議使用 GitOps 或註解管理。

查看狀態:

kubectl get deploy
kubectl get rs

你會看到一個由 Deployment 產生、名稱帶有 hash 的 ReplicaSet。

觸發滾動更新 (Rolling Update)

假設我們要將 Nginx 版本從 1.14.2 升級到 1.21.6。 可以直接修改 YAML 檔案並 apply,或者使用指令:

kubectl set image deployment/nginx-deploy nginx=nginx:1.21.6

觀察更新過程:

kubectl get rs

你會看到:

  • 新的 RS 正在增加副本數 (0 -> 1 -> 2 -> 3)
  • 舊的 RS 正在減少副本數 (3 -> 2 -> 1 -> 0)

透過 kubectl rollout status 可以監控進度:

kubectl rollout status deployment/nginx-deploy

版本回滾 (Rollback)

如果新版本有 Bug,需要緊急切回上一版:

kubectl rollout undo deployment/nginx-deploy

查看歷史版本:

kubectl rollout history deployment/nginx-deploy

擴展與縮減 (Scaling)

當流量增加時,我們可以快速擴展 Pod 的數量:

kubectl scale deployment nginx-deploy --replicas=5

當流量減少時,再縮減回來:

kubectl scale deployment nginx-deploy --replicas=3
在生產環境中,更建議使用 HPA (Horizontal Pod Autoscaler) 根據 CPU 或記憶體使用量自動調整副本數。

重新啟動 (Restart)

當你更新了 ConfigMap 或 Secret,但沒有修改 Deployment 的 image tag 時,Pod 不會自動更新。這時可以使用 rollout restart 來觸發滾動更新,讓 Pod 重新讀取最新的設定配置:

kubectl rollout restart deployment/nginx-deploy

這會像一般的滾動更新一樣,逐個替換 Pod,不會造成服務中斷。

暫停與恢復 (Pause & Resume)

在更新過程中,你可以隨時暫停更新,例如為了檢查新版本的 Pod 是否正常運作(類似金絲雀發佈的手動版):

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

確認沒問題後,再恢復繼續更新:

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

常見更新策略

1. RollingUpdate (滾動更新 - 預設)

這是最常用的策略,透過邊殺邊建的方式,確保服務不中斷。 你可以透過 maxSurgemaxUnavailable 控制更新的速度與風險(如上方的 YAML 範例)。

2. Recreate (重建)

先殺光所有舊的 Pod,再建立新的 Pod。這會導致服務中斷 (Downtime),但適用於 不支援多版本同時運行 的應用程式(例如資料庫 schema 變更不相容時)。

設定方式:

spec:
  strategy:
    type: Recreate

結論

Deployment 是 K8s 中最核心的資源之一。掌握它,你就掌握了應用程式的部署與生命週期管理。 不過,Deployment 適用於 無狀態 (Stateless) 應用(如 Web Server)。 如果你的應用程式需要固定的網路 ID 或持久化儲存順序(如資料庫),那麼你需要的是 StatefulSet