iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0

昨天把 todo-api 和 todo-app-frontend 都用 Deployment 跑起來了。今天來學 Rolling Update——在不停機的情況下更新服務版本 !


什麼是 Rolling Update

傳統的部署方式是「停掉舊版本、啟動新版本」,中間有一段服務中斷的時間。對生產環境來說,這段停機時間是無法接受的。

Rolling Update(滾動更新)的做法是:逐批替換舊版本的 Pod,每次只換一部分,確保隨時都有 Pod 在服務流量。

更新前:[v1] [v1] [v1]

更新中:[v2] [v1] [v1]   ← 先換一個
        [v2] [v2] [v1]   ← 再換一個
        [v2] [v2] [v2]   ← 全部換完

更新後:[v2] [v2] [v2]

整個過程中服務從未中斷,使用者完全感覺不到版本在切換。


Deployment 怎麼做到不停機更新

更新的時候,Deployment 不是直接修改現有的 ReplicaSet,而是:

  1. 建立一個新的 ReplicaSet(跑新版本的 Pod)
  2. 新 ReplicaSet 逐漸增加 Pod 數量
  3. 舊 ReplicaSet 同步減少 Pod 數量
  4. 直到新 ReplicaSet 完全接手,舊 ReplicaSet 縮為 0
更新前:
  舊 ReplicaSet (v1)  → [Pod] [Pod] [Pod]
  新 ReplicaSet (v2)  → (尚未建立)

更新中:
  舊 ReplicaSet (v1)  → [Pod] [Pod]
  新 ReplicaSet (v2)  → [Pod]

更新後:
  舊 ReplicaSet (v1)  → (保留但縮為 0,用於 rollback)
  新 ReplicaSet (v2)  → [Pod] [Pod] [Pod]

舊 ReplicaSet 保留下來是為了 rollback——萬一新版本有問題,可以直接切回舊的。


實際操作

今天目標:幫 todo-api 設定滾動更新策略,推一個 v2 版本上去,親眼看 Pod 逐批替換的過程,並試試 rollback。

Step1: 設定更新策略

  1. 調整 Todo-App/k8s/todo-api-deployment.yaml ,在 Deployment YAML 裡加上 strategy 欄位,控制滾動更新的行為:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: todo-api
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # 更新期間最多多出幾個 Pod
      maxUnavailable: 0  # 更新期間最多有幾個 Pod 不可用
  selector:
    matchLabels:
      app: todo-api
  template:
    metadata:
      labels:
        app: todo-api
        tier: backend
    spec:
      containers:
        - name: api
          image: yourname/todo-app-api:v1.0.0
          ports:
            - containerPort: 8000
          env:
            - name: DATABASE_URL
              value: "mysql+pymysql://user:password@mysql-service:3306/tododb"

兩個關鍵參數:

  • maxSurge: 1:更新期間允許多出 1 個 Pod。3 個副本 + maxSurge 1 = 最多同時存在 4 個 Pod。
  • maxUnavailable: 0:更新期間不允許任何 Pod 不可用。這保證了「隨時都有足夠的 Pod 在服務流量」,適合對可用性要求高的服務。
  1. 套用這份更新後的 YAML:
kubectl apply -f todo-api-deployment.yaml

Step2: 推v2版本到Docker hub

docker buildx build --platform linux/amd64,linux/arm64 \
  -t <你的Docker Hub帳號>/todo-app-api:v2.0.0 \
  --push ./backend

Step3: 觸發 Rolling Update

更新 image 版本來觸發滾動更新:

# 方法一:直接用指令更新 image
kubectl set image deployment/todo-api api=yourname/todo-app-api:v2.0.0

# 方法二:修改 YAML 裡的 image tag,再 apply
# image: yourname/todo-app-api:v2.0.0
kubectl apply -f todo-api-deployment.yaml

Step4: 觀察更新過程

# 即時觀察 Pod 的狀態變化
kubectl get pods -w

你會看到類似這樣的輸出:

NAME                        READY   STATUS              RESTARTS   AGE
todo-api-6d4b9f8c7-k2xpq   1/1     Running             0          5m
todo-api-6d4b9f8c7-m9wvr   1/1     Running             0          5m
todo-api-6d4b9f8c7-x7bnp   1/1     Running             0          5m
todo-api-7f9c8d6b4-ab1cd   0/1     ContainerCreating   0          2s   ← 新版本 Pod 建立
todo-api-7f9c8d6b4-ab1cd   1/1     Running             0          8s   ← 新版本 Pod 就緒
todo-api-6d4b9f8c7-k2xpq   1/1     Terminating         0          5m   ← 舊版本 Pod 開始終止

可能會看到 todo-frontend報錯,先暫時不理它,下一章節建立service就會修復了

確認更新狀態:

kubectl rollout status deployment/todo-api
Waiting for deployment "todo-api" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "todo-api" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "todo-api" rollout to finish: 1 old replicas are pending termination...
deployment "todo-api" successfully rolled out

Step5: 查看更新歷史

kubectl rollout history deployment/todo-api

https://ithelp.ithome.com.tw/upload/images/20260917/201838634DszdYsAWl.png

CHANGE-CAUSE 預設是空的。可以在 apply 的時候加上 annotation 記錄原因:

kubectl annotate deployment/todo-api kubernetes.io/change-cause="update api to v2.0.0"

之後再看 history 就會有記錄:

https://ithelp.ithome.com.tw/upload/images/20260917/20183863A6dYs6c4ea.png

Step6: Rollback

新版本上線後發現有問題,rollback 回上一個版本:

# 回到上一個版本
kubectl rollout undo deployment/todo-api

# 回到指定版本
kubectl rollout undo deployment/todo-api --to-revision=1

rollback 本身也是一次 Rolling Update,K8s 會用同樣的滾動方式把 Pod 換回舊版本,不會停機。

確認 rollback 完成:

kubectl rollout status deployment/todo-api
kubectl get pods

延伸筆記:更新策略的兩種選擇

K8s 的 Deployment 支援兩種更新策略,RollingUpdate 是預設,另一種是 Recreate。

RollingUpdate(預設)

逐批替換 Pod,服務不中斷。適合大多數情況,特別是對可用性要求高的服務。

缺點是更新過程中會同時存在新舊兩個版本,如果新舊版本之間有不相容的資料庫 schema 變更,需要特別處理。

Recreate

先把所有舊版本 Pod 全部刪掉,再建立新版本 Pod。中間會有短暫停機。

strategy:
  type: Recreate

什麼時候用 Recreate?當新舊版本完全不能同時存在的時候——例如資料庫 migration 必須在舊版本完全關閉後才能執行,或者服務用了不支援多副本的本地狀態。

大多數情況會用 RollingUpdate ,除非有明確的理由需要 Recreate。


小結

今天學了 Rolling Update:

  • Rolling Update 逐批替換 Pod,確保更新過程中服務不中斷
  • ReplicaSet 是背後的機制:新 ReplicaSet 逐漸增加、舊 ReplicaSet 逐漸縮小
  • maxSurge / maxUnavailable 控制更新的速度和可用性保證
  • rollback 隨時可以切回上一個版本,本身也是一次滾動更新

明天會學 Service,把 todo-api 和 todo-frontend 串起來,讓它們可以互相溝通,外部也能連進來。


上一篇
Day 06|Deployment
下一篇
Day 08|Service
系列文
從零學 K8s|30 天核心概念 × 實作,新手也能真正掌握 Kubernetes 共 15 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言