打包與部署:Helm 與 Kustomize
· tech
📑 目錄
前面每一篇都在教你寫 YAML,但實務有個逃不掉的痛:同一個 app 要上 Development、Staging、Production,而三個環境九成的 YAML 一模一樣,只有幾個地方不同——副本數、映像 tag、資源大小、對外網址。如果你 copy-paste 三份各自維護,改一個共同欄位就要同步三次,遲早出錯。這篇談兩個解決這件事的主流工具:Helm 與 Kustomize,以及它們背後兩種很不一樣的世界觀。
兩種哲學:模板填空 vs 疊加補丁
Helm 與 Kustomize 都在解「一份來源 + 每環境差異」,但路數南轅北轍。一個把 YAML 當有變數的模板去填,一個把 YAML 當資料去疊補丁:
Helm:把 K8s app 變成可安裝、可版控、可回滾的套件
Helm 常被叫做「K8s 的套件管理器」,類比 apt / npm 很貼切。它的核心是 chart——一個資料夾,裝著 Chart.yaml(套件資訊)、values.yaml(預設值)、和 templates/(帶變數的 YAML 模板)。部署就三個動作:
helm install web ./mychart -f values-prod.yaml # 安裝一個 release,套 prod 的值
helm upgrade web ./mychart -f values-prod.yaml # 改版:同一個 release 升上去
helm rollback web 3 # 一鍵回滾到第 3 版
它比純 YAML 多給你的,是套件管理器該有的東西:每次 install/upgrade 都是一個有版本號的 release,壞了 helm rollback 秒退;還能宣告相依套件(我的 app 需要一個 Redis)。最爽的是現成生態系——要在叢集裡跑 Redis、Prometheus、cert-manager?helm install 一行,不用自己拼幾百行 YAML。代價是那套 Go 模板語言:{{ }}、縮排、條件與迴圈堆起來,複雜的 chart 可以難讀難 debug(這時 helm template 先把它渲染出來看,是保命技)。
Kustomize:純 YAML,base + overlay 疊出各環境
Kustomize 走另一條路:不要模板、不要變數,一切都是合法的 YAML。 你寫一份 base/(本身就能 kubectl apply 的完整 YAML),再為每個環境寫一個 overlays/<env>/,裡面只放這個環境要改的那一小塊 patch:
# overlays/prod/kustomization.yaml
resources: [../../base] # 疊在 base 上
replicas:
- name: web
count: 10 # Production 改成 10 份,其餘全繼承 base
images:
- name: app
newTag: "1.4" # 換 image tag
它內建在 kubectl 裡(kubectl apply -k overlays/prod),不用裝額外工具,還附一堆好用的 transformer:namePrefix、commonLabels、images(改 tag)、replicas,以及 configMapGenerator——後者會在 ConfigMap 名字後面接一段內容 hash,內容一改、名字就變,於是 Pod 樣板跟著變、自動觸發滾動更新。這正好順手解掉第三篇那個坑:改了 ConfigMap 不會自動重啟 Pod——用 Kustomize 的 generator,這件事免費就對了。
該用哪個?
不必二選一,但方向很清楚:
| 情境 | 偏 Helm | 偏 Kustomize |
|---|---|---|
| 裝第三方現成 app(Redis、Prometheus) | ✓ 一行安裝、有生態系 | |
| 管自己的 app manifests | ✓ 純 YAML、好讀好 review | |
| 要版本化 / 一鍵 rollback / 相依管理 | ✓ release 機制 | |
| 重度參數化、要發給別人用 | ✓ values 就是參數面板 | |
| 不想多裝工具、不想學模板語言 | ✓ 內建在 kubectl |
實務上很多團隊兩個都用:第三方套件用 Helm 裝,自家 app 用 Kustomize 疊環境;甚至用 Helm 的 post-renderer 再過一手 Kustomize。先看你要解的是「安裝別人的套件」還是「把自己的 YAML 分環境」——這一題基本就決定了你該先拿哪把。
反思
「模板」與「疊加」是兩種心智負擔,選你受得了的那種
Helm 與 Kustomize 的差別,表面是工具,底層是你願意把 YAML 當程式、還是當資料。Helm 把 YAML 變成有變數、有邏輯的模板——強大,但你多背了一層模板語言的認知稅,出錯時得先在腦中「渲染」才知道實際長怎樣。Kustomize 堅持一切都是合法 YAML,你隨時 kubectl apply -k 就能看到最終結果,心智模型乾淨,代價是遇到高度動態的參數化會綁手綁腳。我自己的偏好是能用 Kustomize 就用 Kustomize——純 YAML 的可讀性與可 review 性,在團隊裡的長期價值被嚴重低估;只有當「參數多到像在寫程式」時,我才承認 Helm 的模板是對的工具。
打包是「設定外部化」的最後一哩,兩層一起才真的一份 build 跑遍天下
這篇其實是 ConfigMap/Secret 那篇的延伸。那篇講「把設定從映像檔裡挖出來」,讓同一個映像檔能跑遍所有環境;這篇講「把環境差異從 YAML 裡抽出來」,讓同一份部署來源能生出各環境的 manifest。兩層是同一個理想的上下半場:build 一次、設定與部署差異全外部化,一份產物跑遍 Dev 到 Production。 少了任何一層,你都會在某個環節退回去 copy-paste。想通這點,我看 CI/CD 的角度也變了——好的 pipeline,不是「為每個環境各建一次」,而是「建一次,靠設定與 overlay 把它擺進不同環境」。
別為了看起來專業,把簡單的事 Helm 化
最後照例潑冷水。我看過小專案、兩三個環境,一上來就搞一個滿是 {{ }} 的自製 Helm chart,結果每次改個副本數都要跟模板語言搏鬥——把本來三行 diff 能解決的事,包成一個要維護的套件。 打包工具是拿來降低跨環境的重複與風險的,不是拿來展示技術棧的。我的順位一律是 先確認痛點、再上重武器:環境少、差異小,raw YAML 或薄薄一層 Kustomize 就夠;真的多環境、多團隊、要發佈共用,才值得 Helm 那套機制。工具的重量,要配得上問題的重量——這是我走完整個 K8s 系列後,最想留下的一句總結。