
在容器化技術的演進過程中,我們經歷了從 Docker 到 Kubernetes 的轉變:
Docker 時代:
docker run 就能啟動應用Kubernetes 時代:
Helm 的出現:
但 Helm 也帶來了新的挑戰:
想像你要在 Kubernetes 上部署一個完整的 Web 應用,你需要:
如果每個環境(開發、測試、正式)都要手動寫這些 YAML,你會發現:
❌ 問題一:檔案爆炸
❌ 問題二:參數混亂
nginx:1.20,正式用 nginx:1.21❌ 問題三:版本管理困難
Helm 就像 Kubernetes 的「套件管理器」,把多個 YAML 檔案打包成一個「Chart」:
✅ 一個 Chart 搞定所有環境
values.yaml 控制不同環境的參數helm install my-app ./my-chart -f dev-values.yamlhelm install my-app ./my-chart -f prod-values.yaml✅ 版本管理與回滾
helm rollback my-app 2 立即回滾✅ 豐富的生態圈
簡單說: Helm 讓你在 K8s 上部署應用就像安裝手機 App 一樣簡單!
my-web-app/ ├── Chart.yaml # 應用資訊(名稱、版本) ├── values.yaml # 預設設定 ├── templates/ # YAML 模板 │ ├── deployment.yaml │ ├── service.yaml │ └── ingress.yaml └── charts/ # 其他依賴的應用
模板檔案(templates/deployment.yaml):
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.app.name }} # 這裡會被替換
spec:
replicas: {{ .Values.replicas }} # 這裡會被替換
template:
spec:
containers:
- name: {{ .Values.app.name }}
image: {{ .Values.image }}:{{ .Values.tag }}
設定檔案(values.yaml):
app: name: "my-web-app" replicas: 3 image: "nginx" tag: "1.21"
最終產生的 YAML:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-web-app
spec:
replicas: 3
template:
spec:
containers:
- name: my-web-app
image: nginx:1.21
開發環境(dev-values.yaml):
replicas: 1 image: "nginx" tag: "1.20"
正式環境(prod-values.yaml):
replicas: 3 image: "nginx" tag: "1.21"
# macOS brew install helm # Linux curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash # Windows choco install kubernetes-helm
helm repo add elastic https://helm.elastic.co helm repo update
helm install elasticsearch elastic/elasticsearch
就這樣!Elasticsearch 開始部署了。
# 查看所有已安裝的應用 helm list # 查看 Elasticsearch 的詳細狀態 helm status elasticsearch # 查看部署歷史 helm history elasticsearch
# 升級到新版本 helm upgrade elasticsearch elastic/elasticsearch --set imageTag=8.5.0 # 如果出問題,回滾到上一個版本 helm rollback elasticsearch
deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-dev
spec:
replicas: 1
template:
spec:
containers:
- name: nginx
image: nginx:1.20
service.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-dev-service
spec:
selector:
app: nginx-dev
ports:
- port: 80
正式環境還要再寫一套類似的檔案…
一個命令搞定:
# 開發環境 helm install nginx bitnami/nginx --set replicaCount=1,imageTag=1.20 # 正式環境 helm install nginx bitnami/nginx --set replicaCount=3,imageTag=1.21
差異對比:
| 項目 | 純 YAML | Helm |
|---|---|---|
| 檔案數量 | 環境數 × 資源數 | 1 個 Chart |
| 參數管理 | 手動修改每個檔案 | 統一 values.yaml |
| 版本控制 | 手動記錄 | 自動版本管理 |
| 回滾 | 手動重建 | helm rollback |
| 生態圈 | 自己寫 | 數千個現成 Chart |
# 基本操作 helm list # 查看已安裝的應用 helm status <app-name> # 查看應用狀態 helm history <app-name> # 查看部署歷史 # 安裝與升級 helm install <name> <chart> # 安裝應用 helm upgrade <name> <chart> # 升級應用 helm uninstall <name> # 刪除應用 # 回滾 helm rollback <name> <revision> # 回滾到指定版本 helm rollback <name> # 回滾到上一個版本 # 查看與下載 helm search repo <keyword> # 搜尋可用的 Chart helm pull <chart> # 下載 Chart 到本地 helm template <chart> # 預覽會產生的 YAML
很多人好奇 helm rollback 是如何快速回滾的,其實背後的原理並不複雜:
每次執行 helm install 或 helm upgrade,Helm 都會建立一個 Release,並記錄版本號(Revision):
# 查看部署歷史 helm history my-app # 輸出範例: REVISION STATUS CHART DESCRIPTION 1 superseded my-app-1.0.0 Install complete 2 superseded my-app-1.0.1 Upgrade complete 3 deployed my-app-1.0.2 Upgrade complete
Helm 會把每個 Revision 的完整資訊儲存在 Kubernetes 的 Secret 中:
# 查看 Helm 建立的 Secret kubectl get secrets -l owner=helm # 輸出範例: NAME TYPE DATA sh.helm.release.v1.my-app.v1 helm.sh/release.v1 1 sh.helm.release.v1.my-app.v2 helm.sh/release.v1 1 sh.helm.release.v1.my-app.v3 helm.sh/release.v1 1
每個 Secret 包含:
當你執行 helm rollback my-app 2 時,Helm 會:
┌─────────────────────────────────────────────────────────┐
│ 1. 讀取目標版本 │
│ 從 Secret sh.helm.release.v1.my-app.v2 取出資料 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 2. 解壓縮並解碼 │
│ Secret 內容是 base64 + gzip 壓縮的 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 3. 取得舊版 Manifest │
│ 獲得當時產生的完整 Kubernetes YAML │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 4. 執行三方合併(Three-way Merge) │
│ 比對:舊版 Manifest vs 現有狀態 vs 目標版本 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 5. 套用變更 │
│ 透過 kubectl apply 將資源更新到目標狀態 │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 6. 建立新的 Revision │
│ Rollback 本身也會建立一個新版本(如 v4) │
└─────────────────────────────────────────────────────────┘
# 取得特定版本的 Release 資料
kubectl get secret sh.helm.release.v1.my-app.v2 -o jsonpath='{.data.release}' | base64 -d | gunzip
# 會輸出 JSON 格式的完整 Release 資訊,包含:
# - chart: Chart 的完整內容
# - config: 當時的 values
# - manifest: 產生的 YAML
# - version: 版本號
⚠️ Secret 有大小限制:Kubernetes Secret 預設最大 1MB,如果 Chart 很大可能會有問題
⚠️ 歷史版本會累積:預設保留 10 個版本,可透過 --history-max 調整:
helm upgrade my-app ./my-chart --history-max 5
⚠️ Rollback 不會還原資料:只會還原 Kubernetes 資源設定,資料庫等持久化資料不會回滾
| 項目 | Helm Rollback | kubectl rollout undo |
|---|---|---|
| 範圍 | 整個 Release(多個資源) | 單一 Deployment |
| 歷史儲存 | Kubernetes Secret | ReplicaSet |
| 設定還原 | 完整還原(含 values) | 只還原 Pod 模板 |
| ConfigMap/Secret | ✅ 會還原 | ❌ 不會還原 |
很多人會問:「Helm 的 Revision 和 Git commit 有什麼關係?」
答案是:兩者是完全獨立的系統,沒有直接關聯。
┌─────────────────────────────────────────────────────────────────┐ │ 兩套獨立的版本系統 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ Git(原始碼版本控制) Helm(部署版本控制) │ │ ├── commit abc123 ├── Revision 1 │ │ ├── commit def456 ├── Revision 2 │ │ ├── commit ghi789 ├── Revision 3 │ │ └── 儲存在 Git Repository └── 儲存在 K8s Secret │ │ │ └─────────────────────────────────────────────────────────────────┘
它們追蹤的東西不同:
| 項目 | Git | Helm Revision |
|---|---|---|
| 追蹤對象 | 原始碼變更 | 部署狀態變更 |
| 儲存位置 | Git Repository | Kubernetes Secret |
| 版本格式 | SHA hash(如 abc123) | 遞增數字(1, 2, 3…) |
| 回滾影響 | 程式碼回到過去 | K8s 資源回到過去 |
為什麼會獨立?
部署不一定對應程式碼變更
replicas: 3 → replicas: 5(沒有程式碼變更)一次 commit 可能多次部署
部署可能失敗重試
實務上如何關聯?
雖然兩者獨立,但在 CI/CD 流程中,我們通常會透過 標籤(Label)或註解(Annotation) 來關聯:
# 在 values.yaml 或部署時加入 Git 資訊
metadata:
annotations:
git.commit: "abc123def"
git.branch: "main"
git.repo: "github.com/myorg/myapp"
部署時帶入 Git 資訊:
# 在 CI/CD 中自動帶入 Git commit helm upgrade my-app ./chart \ --set gitCommit=$(git rev-parse --short HEAD) \ --set gitBranch=$(git branch --show-current)
這樣做的好處:
總結: Helm 透過把每個版本的完整資訊存在 Secret 中,實現了快速且完整的回滾機制。這也是為什麼 Helm 比手動管理 YAML 更可靠的原因之一。
Q: Helm 會影響現有的 Kubernetes 資源嗎? A: 不會。Helm 只是管理工具,不會影響已經存在的資源。
Q: 可以同時使用 Helm 和 kubectl 嗎? A: 可以。Helm 最終還是透過 kubectl 與 Kubernetes 互動。
Q: 如果 Chart 出問題怎麼辦?
A: 用 helm rollback 回滾,或 helm uninstall 刪除後重新安裝。
Q: 自建 Chart 很複雜嗎? A: 一開始可能有點複雜,但熟悉後會比手寫 YAML 簡單很多。
Helm 讓 Kubernetes 應用部署變得:
如果你還在手寫一堆 YAML 檔案,建議試試 Helm,會發現新世界!