大家好!來到 Day 8啦
今天要跟大家談的是 要怎麼做到不中斷的去更新。
假設 API 有三個 Pod:
v1
v1
v1
現在要改上:
v2
最暴力的方法:
把三個 v1 全殺掉
再建立三個 v2
結果:
中間一段時間
沒有任何 API。
(這就是允許系統會暫時壞掉的情況)
這就是 Deployment Rolling Update 要解決的事情。
kubectl get deployment api \
-n cka-lab \
-o jsonpath='{.spec.template.spec.containers[0].image}'
如果前面沿用:
nginx:alpine
現在更新:
kubectl set image \
deployment/api \
nginx=nginx:1.27-alpine \
-n cka-lab
注意 nginx= 前面的 nginx 是:
Container Name
不是 Deployment Name。

kubectl rollout status \
deployment/api \
-n cka-lab

同時另一個 Terminal:
kubectl get pods -n cka-lab -w
-w:
Watch。
你會看到舊 Pod 與新 Pod 有一段時間同時存在。

kubectl get rs -n cka-lab
現在很可能看到:
舊 ReplicaSet
新 ReplicaSet
因為 Deployment 的 Pod Template 改變了。
因此:
Deployment
├── Old ReplicaSet → v1
└── New ReplicaSet → v2
新的 ReplicaSet 慢慢 Scale Up。
舊的慢慢 Scale Down。
這就是 Rolling Update。
kubectl rollout history \
deployment/api \
-n cka-lab
可以查看 Revision。
如果 Deployment YAML 有:
kubernetes.io/change-cause
等資訊,也能更容易辨識版本。
現在我們故意做:
kubectl set image \
deployment/api \
nginx=nginx:this-version-does-not-exist \
-n cka-lab

看看:
kubectl get pods -n cka-lab
會看到:
ImagePullBackOff

這是我們第一次故意製造真正的 Kubernetes 問題。
kubectl describe pod <BROKEN_POD的名字> -n cka-lab
找到 Events。
你會看到類似:
Failed to pull image

這時我們才知道:
不是 Application Crash
不是 Probe
不是 Network
而是:
Image 根本抓不到。
kubectl rollout undo \
deployment/api \
-n cka-lab
kubectl rollout undo):

接著:
kubectl rollout status \
deployment/api \
-n cka-lab
kubectl rollout status):
status 指令會卡住執行緒,若成功退出狀態碼為 0;若超時或失敗會報錯退出,讓自動化流程能捕捉到錯誤。核心結論: 第一個指令已經完成 rollback 的宣告;第二個指令是為了「確定它順利跑完了」,而不是觸發 rollback 的必要條件。

Deployment 回到上一個 Revision。
這就是:
Rollback。
在現代生產環境(Production)中,kubectl rollout undo 已經不太常作為常規手段使用,甚至被多數團隊視為「緊急避難用的反模式(Anti-pattern)」。
但在兩種情境依然常用:
破壞 Single Source of Truth(單一真相來源):
現代團隊普遍採用 GitOps(如 ArgoCD、Flux)或 IaC / CI/CD Pipeline(如 Helm、GitLab CI、GitHub Actions)。
如果你用 kubectl rollout undo 直接改了叢集狀態,你的 Git 儲存庫裡紀錄的依然是壞掉的版本。一旦下次有其他人 Merge 程式碼或 GitOps 自動同步(Reconcile),叢集又會被覆蓋回壞掉的版本。
追蹤與稽核困難: 手動敲指令缺乏 Code Review、審核日誌與版本追蹤。
不用手動敲叢集指令,而是回到代碼與配置本身:
git revert <commit-id>。Helm 是 Kubernetes 的套件管理器(Package Manager),常被形容為 Kubernetes 世界裡的 apt、yum 或 brew。
在沒有 Helm 之前,如果要部署一個應用(例如 WordPress 或一套微服務),你需要手動寫好並維護一堆 YAML 檔案:deployment.yaml、service.yaml、ingress.yaml、secret.yaml、pvc.yaml...,然後一行一行敲 kubectl apply -f。當架構變得複雜、或需要區分開發/測試/正式環境時,純手動維護 YAML 會極易出錯且難以管理。
Helm 的出現就是為了解決這個痛點。
要理解 Helm,只要掌握以下三個主要組件:
redis-cache 和 redis-queue,它們是兩個獨立的 Release。1. 樣板化與環境分離(Templating & Values)
傳統 YAML 是靜態死板的,而 Helm 引入了模板引擎(Go Template)。
你可以把程式碼固定成範本,並將變數抽離到 values.yaml。切換環境時,只需帶入不同的設定檔:
# 部署到開發環境
helm install my-app ./my-chart -f values-dev.yaml
# 部署到正式環境
helm install my-app ./my-chart -f values-prod.yaml
2. 一鍵安裝與依賴管理
如果你的服務依賴於 MySQL,傳統做法要先搞定 MySQL 的 PVC、StatefulSet,再部署主服務。Helm 支援依賴宣告(Subcharts),執行 helm install 時會自動幫你連帶把相依的套件一併起好。
3. 版本控制與歷史追蹤(Release Management)
每次使用 Helm 更新服務,它都會在叢集裡記錄一個新的版本號(Revision)。
你可以隨時檢視歷史,甚至一鍵回滾:
# 檢視歷史發布紀錄
helm history my-app
# 直接回滾到版本 2
helm rollback my-app 2
| 功能維度 | 原生 kubectl |
使用 Helm |
|---|---|---|
| 部署方式 | 個別 YAML 檔案分次或批次 apply |
將整個應用打包為一個 Chart 一鍵安裝 |
| 參數代換 | 靜態 YAML(需額外靠 sed、kustomize 處理) | 動態變數注入(values.yaml) |
| 套件共享 | 複製貼上 YAML | 透過 Repository 下載現成社群套件 |
| 升級與回滾 | 需要個別對 Deployment 操作,設定檔無集中版本 | Release 概念統一追蹤整個系統狀態,支援全套件回滾 |
| 刪除應用 | 需分別 delete 多個資源,容易遺漏 |
helm uninstall <release> 一次性清除所有關聯資源 |
現在的主流雲原生架構中,Helm 幾乎是必備工具,並且常常搭配 GitOps 工具(如 ArgoCD、Flux)一起使用:將 Helm Chart 與 values 放在 Git 儲存庫中,由 GitOps Controller 自動將變更同步到 Kubernetes 叢集。
若應用程式是用 Helm 部署的,通常不會直接操作 kubectl,而是使用 Helm 的版本追蹤:
Bash
helm rollback <release-name> <revision-number>
這會記錄一次明確的 Helm Release 變更,不會造成配置與 Release History 的脫鉤。
後面的 Day 25,將會再對 Helm 做詳細介紹,這邊先有個觀念即可。
透過 Argo Rollouts 或 Flagger:
ImagePullBackOff 為什麼叫 BackOff?Kubernetes 不會:
每一毫秒狂抓 Image。
失敗後會逐漸拉長重試時間。
所以:
BackOff
就是暫時退避。
這個概念不只會出現在 Image。
之後還會看到:
CrashLoopBackOff
也是類似概念。
今天真正建立的直覺:
Deployment 更新
↓
產生新 ReplicaSet
↓
新 Pod 漸增
↓
舊 Pod 漸減
↓
完成 Rolling Update
如果出問題:
rollout history
rollout status
rollout undo
這三個指令要開始熟悉。
明天我們碰 Kubernetes 最常讓初學者困惑的一層:
Pod 明明都有自己的 IP,那為什麼還需要多 Service 這一層呢?