前面幾天,我們已經親手寫過很多 Kubernetes Resource:
Deployment
Service
ConfigMap
Secret
PVC
NetworkPolicy
RBAC
這段過程其實非常重要。因為如果一開始就直接學 Helm,你可能會很熟:
helm install
但不知道 Helm 背後究竟替你產生了哪些 Deployment、Service、ConfigMap。
現在開始學 Helm 與 Kustomize,時機反而剛剛好,因為我們已經親自遇到一個 Kubernetes 專案很自然會出現的問題:
YAML 越來越多。
而且目前 CKA 的官方考試範圍也明確包含:
使用 Helm 與 Kustomize 安裝 Cluster Components。
所以這兩個工具不只是實務常見,也確實是現在準備 CKA 應該掌握的內容。
假設我們有一個 API:
api
在自己電腦上的 Local Environment,也就是「本機開發環境」,可能只需要:
replicas: 1
但 Production Environment,也就是正式對外服務的「正式環境」,可能需要:
replicas: 5
最直覺的做法可能是複製三份:
deployment-local.yaml
deployment-staging.yaml
deployment-prod.yaml
一開始看起來沒什麼問題,但這三份檔案可能有 95% 都完全一樣。
真正麻煩的是半年後。
例如你修改了 Local 的:
readinessProbe
卻忘記修改 Production;Production 後來又調整了 Resource Limit,但是 Staging 沒同步。
久而久之,三套 YAML 就開始長得不一樣。
這種「原本應該維持一致的設定,隨著時間逐漸產生差異」的現象,就叫做:
Configuration Drift,設定漂移。
Kustomize 主要就是用來解決這類問題。

image source: https://devopscube.com/kustomize-tutorial/
Kustomize 是 Kubernetes YAML 的客製化工具。
它的核心想法不是另外發明一套 Kubernetes 語法,而是:
先保留一份共同 YAML
+
不同環境只寫「差異」的部分
這就是 Kustomize 最重要的兩個名詞:
Base
Overlay
Base 是大家共同使用的 Kubernetes Configuration,例如 Deployment、Service。
Overlay 則代表某個特定環境要修改的部分,例如:
Local → replicas = 1
Production → replicas = 5
最後 Kustomize 會把:
Base
+
Overlay
組合成真正完整的 Kubernetes YAML。
如果你已經安裝 kubectl,我們目前這種用法通常不需要再額外安裝 Kustomize,因為 kubectl 已經整合了 Kustomize,可以直接使用:
kubectl kustomize
官方文件也直接提供 kubectl kustomize DIR 來產生 Kustomization 的結果。
可以先確認:
kubectl version --client
只要 kubectl 正常,就可以繼續。

我們現在要開始把原本的 Kubernetes YAML 改成 Kustomize 可以管理的結構。
目前你的專案原本就有:
k8s/
├── 00-namespace.yaml
├── 01-api.yaml
├── 02-configmap.yaml
├── 03-secret.yaml
├── 04-redis.yaml
├── 05-postgres-pvc.yaml
├── 06-postgres.yaml
├── default-deny-ingress.yaml
└── redis-networkpolicy.yaml
其中我們已經確認:
k8s/01-api.yaml
裡面的 Deployment 名稱是:
kind: Deployment
metadata:
name: api
namespace: cka-lab
而且 01-api.yaml 本身可以同時包含 Deployment、Service 等多個 Kubernetes Resource,所以我們不需要硬把它拆成 deployment.yaml 和 service.yaml。
Kustomize 不在意一個 YAML 裡面有幾個 Resource,它只需要知道:
哪些 YAML 是所有環境共同使用的。
這些共同設定就會放進 Base。
回到:
k8s-30days/
專案根目錄,建立:
mkdir -p deploy/base
mkdir -p deploy/overlays/local
mkdir -p deploy/overlays/production
這裡:
base/
用來存放所有環境共用的 Kubernetes 設定。
而:
overlays/
則用來存放不同環境的差異,例如:
local
production
最後目錄會先變成:
deploy/
├── base/
│
└── overlays/
├── local/
└── production/
我們先拿目前的:
k8s/01-api.yaml
做 Kustomize 練習。
複製到 Base:
cp k8s/01-api.yaml deploy/base/api.yaml
這裡只是把檔名從:
01-api.yaml
改成比較單純的:
api.yaml
內容本身不需要改。
現在:
ls deploy/base
應該會看到:
api.yaml
所以目前結構是:
deploy/
├── base/
│ └── api.yaml
│
└── overlays/
├── local/
└── production/
而 api.yaml 裡面依然會有我們原本的 Deployment:
kind: Deployment
metadata:
name: api
namespace: cka-lab
這裡的:
name: api
非常重要。
因為等等 Local 和 Production Overlay 想修改這個 Deployment 的 Replica 數量時,就是透過:
api
找到它。
接下來建立:
deploy/base/kustomization.yaml
可以使用:
vim deploy/base/kustomization.yaml
寫入:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- api.yaml
現在 Base 目錄就會變成:
deploy/
├── base/
│ ├── api.yaml
│ └── kustomization.yaml
│
└── overlays/
├── local/
└── production/
這裡第一次看到:
resources:
可以把它理解成:
這一組 Kustomize 設定要包含哪些 Kubernetes YAML。
現在我們只有:
resources:
- api.yaml
意思就是:
Base
↓
包含 api.yaml
而 api.yaml 裡面的 Deployment、Service 等 Resource,都會一起被 Kustomize 載入。
目前我們故意先只把:
01-api.yaml
放進 Base,是為了先把 Base + Overlay 的核心概念學清楚。
等後面理解之後,我們才可以再逐步把:
ConfigMap
Secret
Redis
PVC
PostgreSQL
NetworkPolicy
一起整理進 Base。
到時候可能會變成:
deploy/base/
├── api.yaml
├── configmap.yaml
├── secret.yaml
├── redis.yaml
├── postgres-pvc.yaml
├── postgres.yaml
├── default-deny-ingress.yaml
├── redis-networkpolicy.yaml
└── kustomization.yaml
而 kustomization.yaml 再統一把它們全部列進 resources。
但現在先從:
api.yaml
開始就好,下一步再讓 Local 和 Production Overlay 分別把:
api Deployment
改成不同的 Replica 數量。
接著建立:
vim deploy/overlays/local/kustomization.yaml
內容:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
replicas:
- name: api
count: 1
這裡的:
resources:
- ../../base
意思是:
先把 Base 的全部 Resource 拿進來。
接著:
replicas:
- name: api
count: 1
表示找到:
metadata:
name: api
的 Deployment,將它的:
spec:
replicas:
改成:
1
所以 Local Environment 不需要再複製一份 Deployment。
它只需要記錄:
「我跟 Base 的差別是 replicas = 1。」
建立:
vim deploy/overlays/production/kustomization.yaml
內容:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
replicas:
- name: api
count: 5
現在整個概念就變成:
Base
│
┌────────┴────────┐
│ │
Local Production
replicas=1 replicas=5
我們不再維護三份幾乎相同的 Deployment。
真正共同的東西只存在:
Base
不同環境只保存:
Difference
這就是 Kustomize 最重要的價值。
這裡會出現一個非常重要的名詞:
Render
Render 可以理解成「把設定與修改全部計算完成,產生最後真正的 Kubernetes YAML」。
例如執行:
kubectl kustomize deploy/overlays/local
Kustomize 不會 Deploy。
它只是把:
Base
+
Local Overlay
計算完成,然後把最後的 YAML 印在 Terminal。
就可以看到:

Production 則可以看:
kubectl kustomize deploy/overlays/production
就可以看到:

這是一個非常值得養成的習慣:
Deploy 之前先 Render,看最後究竟會送什麼進 Kubernetes。
Local:
kubectl apply \
-k deploy/overlays/local
這裡要特別注意:
之前的
-f
通常代表:
套用某個 YAML Manifest。
例如:
kubectl apply -f deployment.yaml
但:
-k
代表:
這是一個 Kustomize Directory,請先執行 Kustomize,再 Apply。
所以:
kubectl apply -k deploy/overlays/local
其實可以想成:
讀取 Base
↓
套用 Local Overlay
↓
產生完整 YAML
↓
Apply 到 Cluster
最後確認:
kubectl get deployment api -n cka-lab

如果切成 Production:
kubectl apply \
-k deploy/overlays/production
再查看:
kubectl get deployment api -n cka-lab
Replica 就會變成 5。

Kustomize 很適合:
我已經有 Kubernetes YAML
只是不同環境有一些差異
但另一種情況是:
我要把一整套 Kubernetes Application 包裝起來,讓別人可以安裝、設定、升級甚至 Rollback。
這就是 Helm 擅長的地方。

image source: https://blog.ivansli.com/2024/07/07/240707-helm/
Helm 是 Kubernetes 的 Package Manager,也就是套件管理工具。
你可以把它想成:
macOS → Homebrew
Node.js → npm
Python → pip
Kubernetes → Helm
例如:
Prometheus
Grafana
Argo CD
Redis
這些系統可能一次包含:
Deployment
Service
ConfigMap
Secret
ServiceAccount
RBAC
PVC
如果全部手動複製 YAML 會非常麻煩。
因此別人可以把整套 Application 包裝成:
Helm Chart
然後我們透過:
helm install
安裝。
目前 Helm 4 已經是正式 Stable 主線;官方目前文件也以 Helm 4 為主,而 Chart 本身仍保持高度向後相容。
Kustomize 可以直接透過 kubectl 使用,但 Helm CLI 需要另外安裝。
我們在 macOS 上可以直接:
brew install helm
Helm 官方也列出 Homebrew 作為安裝方式。
確認:
helm version
如果能看到:
v4.x.x
就表示 Helm 已經可以使用。
執行:
helm create cka-api

Helm 會建立一個基本 Chart:
cka-api/
├── Chart.yaml
├── values.yaml
├── charts/
└── templates/
這裡先認識三個最重要的部分。
Chart.yaml 是這個 Package 的 Metadata,也就是名稱、版本、描述等資訊。
例如:
name: cka-api
version: 0.1.0
values.yaml 則是:
使用這個 Chart 的人,可以調整的參數。
而:
templates/
裡面則是真正的 Kubernetes YAML Template。
Template 就是「還沒有完全填好的 YAML」。
例如原本 Deployment 可能直接寫:
spec:
replicas: 2
Helm 可以改成:
spec:
replicas: {{ .Values.replicaCount }}

這裡:
{{ ... }}
就是 Helm Template 語法。
而:
.Values
代表:
values.yaml
裡面的值。
例如 values.yaml:
replicaCount: 2
最後 Helm Render 出來就會變成:
spec:
replicas: 2
例如我們可以在 values.yaml 裡面設定:
replicaCount: 2
image:
repository: cka-api
tag: v4
pullPolicy: IfNotPresent
service:
port: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
Deployment Template 就可以引用:
replicas: {{ .Values.replicaCount }}
Image:
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
因此 Helm 的核心概念其實就是:
Template
+
Values
↓
Rendered Kubernetes YAML
不同環境甚至可以提供不同 Values:
values-local.yaml
values-production.yaml
而不是複製整套 Kubernetes YAML。
跟 Kustomize 一樣,我們應該先養成:
先 Render,再 Deploy。
執行:
helm template \
cka-api \
./cka-api

這裡第一個:
cka-api
是等等 Helm Release 的名字。
第二個:
./cka-api
則是 Chart 的路徑。
helm template 不會修改 Cluster。
它只是把:
Chart
+
Values
+
Templates
全部計算完成,再把真正的 Kubernetes YAML 印出來。
所以 Debug Helm Chart 時:
helm template
非常重要。
這又是一個很容易混淆的新名詞。
Chart 是安裝包。
而:
Release 是這個 Chart 實際安裝到某個 Cluster 後的一個 Instance。
例如:
cka-api Chart
可以安裝成:
cka-api-dev
cka-api-staging
cka-api-prod
這三個就是三個不同 Release。
可以想成:
Chart
=安裝包
Release
=安裝完成的一份實例
安裝:
helm install \
cka-api \
./cka-api \
-n cka-lab
或者直接讓 Helm 在 Namespace 不存在時建立:
helm install \
cka-api \
./cka-api \
-n cka-lab \
--create-namespace

安裝完成後可以看:
helm list -n cka-lab

以及:
kubectl get all -n cka-lab
第一次是:
helm install
之後如果你修改:
Template
Values
Image
Replica
Resources
就不是重新 Install,而是:
helm upgrade \
cka-api \
./cka-api \
-n cka-lab
實務上更常看到:
helm upgrade \
--install \
cka-api \
./cka-api \
-n cka-lab
意思是:
Release 已存在
→ Upgrade
Release 不存在
→ Install
這樣 CI/CD 就不用先判斷到底有沒有安裝過。
每次:
helm install
或:
helm upgrade
Helm 都會替這個 Release 保存一個版本紀錄。
這個版本叫:
Revision

例如:
Revision 1
第一次 Install
Revision 2
修改 replicas
Revision 3
換 Image v5
查看:
helm history \
cka-api \
-n cka-lab

假設 Revision 3 出問題,希望回到 Revision 1:
helm rollback \
cka-api \
1 \
-n cka-lab

Helm 就會把整個 Release 回復到 Revision 1 的狀態。
kubectl rollout undo 跟 helm rollback 不一樣前面我們曾經使用:
kubectl rollout undo deployment/api
它主要是在處理:
Deployment 的 Rollout Revision
例如:
Container Image v4
↓
Container Image v5
↓
回到 v4
但是 Helm Release 裡可能不只有 Deployment。
還可能同時管理:
Deployment
Service
ConfigMap
Secret
RBAC
所以:
helm rollback
處理的是:
整個 Helm Release 的 Revision。
可以簡單記:
kubectl rollout undo
→ Kubernetes Workload
helm rollback
→ Helm Release
這兩個工具其實不是競爭關係。
Kustomize 比較像:
我已經有原生 Kubernetes YAML
↓
我只想針對不同環境 Patch / Overlay
例如:
Local replicas = 1
Production replicas = 5
Helm 比較像:
我要把整套 Kubernetes Application
包裝成可重複安裝的 Package
並且提供:
Values
Install
Upgrade
History
Rollback
所以可以記成:
Kustomize
= Base + Overlay / Patch
Helm
= Chart + Values + Release Management
Production 環境甚至很常兩個一起使用。
真正重要的並不是:
Helm 比較好
或:
Kustomize 比較好
而是你看到問題時,知道它們各自在解決什麼。
我們一路從最開始的:
手寫 Kubernetes YAML
逐漸走到:
Deployment
Service
ConfigMap
Secret
PVC
NetworkPolicy
RBAC
現在才開始加入:
Kustomize
Helm
這個學習順序其實非常重要。
因為現在看到:
helm install
你不會覺得它是一個神奇指令。
你知道它最後依然是在幫你建立:
Deployment
Service
ConfigMap
Secret
...
Kustomize 也不是另一套 Kubernetes。
它只是在幫我們更有系統地管理:
原本就已經會寫的 Kubernetes YAML。
到這裡,我們已經開始從:
「會建立 Kubernetes Resource」
往:
「會管理一整套 Kubernetes Configuration」
前進。
下一步就可以把目前一直依賴的:
localhost:8080
kubectl port-forward
真正往外推進。
我們接下來要處理的是:
External HTTP Traffic
也就是外部使用者究竟要怎麼進入 Kubernetes 裡面的 Application。
而目前 CKA 的考試範圍除了傳統 Ingress,也已經明確納入 Gateway API。
所以下一篇就可以正式進入:
Ingress
Ingress Controller
Gateway API
HTTPRoute
看看一個真正的 HTTP Request,是怎麼從 Cluster 外面一路進到我們的 Pod。