昨天我們從零手寫了一個精簡的 Helm Chart,成功部署了 Nginx。
但仔細看 deployment.yaml 和 service.yaml,會發現同樣的名稱與 Label 重複出現在很多地方,例如:
{{ .Release.Name }}-nginx
以及:
app: {{ .Release.Name }}-nginx
如果哪天想把命名規則從:
<Release.Name>-nginx
改成:
<Release.Name>-<Chart.Name>
就必須到不同模板裡逐一修改。
當 Chart 越來越大、模板越來越多,這種重複不只難維護,也很容易發生漏改。
今天我們要學的,就是用 _helpers.tpl 與進階 Helm Template 技巧,把重複邏輯集中管理,讓 Chart 更有彈性、也更容易維護。
今天內容包含:
_helpers.tpl —— 建立可以重複使用的共用模板define / include —— 定義與引用模板include vs template —— 兩種引用方式有什麼差別with —— 縮小作用域,讓模板更簡潔toYaml / nindent —— 將結構化資料輸出成正確縮排的 YAMLvalues-dev.yaml / values-prod.yaml
if 控制是否建立 Ingress以下操作延續 Day 21 的
my-chart,皆在 master 節點執行。
_helpers.tpl 是什麼?_helpers.tpl 是 Helm Chart 中常用來放置**共用模板片段(helper templates)**的檔案,通常位於 templates/ 目錄下。
它可以把重複使用的名稱、Label 或其他模板邏輯集中定義,再讓 deployment.yaml、service.yaml 等其他模板重複引用。
💡 為什麼檔名用底線
_開頭?
templates/目錄中的大多數檔案都會參與 Helm Template 渲染,並可能產生 Kubernetes Manifest。但檔名以
_開頭的檔案,Helm 會把它視為 partial / helper template,不會直接渲染成 Kubernetes Object。因此
_helpers.tpl很適合當成 Chart 裡的「共用工具箱」,專門放給其他模板引用的共用內容。
可以用程式語言的角度來理解:
_helpers.tpl:像是一個共用函式庫
define:用來定義可重複使用的模板片段include:在其他模板中引用這些共用片段_helpers.tplvim my-chart/templates/_helpers.tpl
輸入以下內容:
{{- define "my-chart.fullname" -}}
{{- printf "%s-nginx" .Release.Name -}}
{{- end -}}
{{- define "my-chart.labels" -}}
app: {{ include "my-chart.fullname" . }}
chart: {{ .Chart.Name }}
release: {{ .Release.Name }}
{{- end -}}
my-chart.fullname —— 集中管理資源名稱的產生邏輯。
例如 Release 名稱是:
my-release
經過:
{{ printf "%s-nginx" .Release.Name }}
會產生:
my-release-nginx
之後如果想修改命名規則,只需要修改 _helpers.tpl 裡這一處。
my-chart.labels —— 集中管理多個資源共用的 Labels。
渲染後會類似:
app: my-release-nginx
chart: my-chart
release: my-release
Deployment、Service 等資源都可以引用同一份 Labels,避免每個模板重複撰寫。
💡 為什麼名稱寫成
my-chart.fullname?Helm 的 Named Template 名稱是全域的,因此通常會加上 Chart 名稱作為前綴,例如:
my-chart.fullname my-chart.labels這樣可以降低不同 Chart 或 Subchart 之間發生命名衝突的機會。
_helpers.tpl現在來改寫 Day 21 的 deployment.yaml 和 service.yaml,把重複的名稱與 Labels 改成引用 _helpers.tpl。
vim my-chart/templates/deployment.yaml
改寫後:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ include "my-chart.fullname" . }}
template:
metadata:
labels:
{{- include "my-chart.labels" . | nindent 8 }}
spec:
containers:
- name: nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.containerPort }}
protocol: TCP
💡 為什麼這裡使用
nindent?
include會回傳一段文字,而 YAML 對縮排非常敏感。
nindent 4會:
- 先加入一個換行
- 再把每一行往右縮排 4 格
這樣很適合把
_helpers.tpl產生的多行內容放進 YAML 結構中。例如:
{{ include "my-chart.labels" . | nindent 4 }}就能把共用 Labels 正確放進
metadata.labels。
vim my-chart/templates/service.yaml
改寫後:
apiVersion: v1
kind: Service
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
selector:
app: {{ include "my-chart.fullname" . }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.containerPort }}
protocol: TCP
| 項目 | Day 21(精簡版) | Day 22(進階版) |
|---|---|---|
| 資源名稱 | 每個模板各自寫 {{ .Release.Name }}-nginx |
統一引用 {{ include "my-chart.fullname" . }} |
| Labels | 每個位置各自撰寫 | 統一引用 {{ include "my-chart.labels" . }} |
| 修改命名規則 | 需要修改多個模板 | 只需要修改 _helpers.tpl |
| 維護方式 | 重複邏輯分散在不同檔案 | 共用邏輯集中管理 |
透過 _helpers.tpl,我們把原本散落在不同模板中的重複邏輯集中到同一個地方。
之後如果想修改資源名稱或共用 Labels,只需要調整 _helpers.tpl,其他引用它的模板就會一起套用新的規則。
include vs template — 差在哪?Helm 有兩種常見方式可以引用 Named Template:
include |
template |
|
|---|---|---|
| 類型 | Function | Action |
| 可以接 Pipeline | ✅ 可以 | ❌ 不行 |
可以搭配 indent / nindent |
✅ 可以 | ❌ 無法直接接 Pipeline |
| 實務使用 | ✅ 通常優先使用 | 適合不需要額外處理輸出的簡單場景 |
例如:
{{ include "my-chart.labels" . | nindent 4 }}
include 會先取得 Named Template 的輸出,再把結果交給 nindent 4 處理。
但 template:
{{ template "my-chart.labels" . }}
會直接把內容插入目前的位置,無法再接:
| nindent 4
💡 實務上優先使用
includeYAML 對縮排非常敏感,而
include可以搭配 Pipeline 使用,例如nindent、indent、quote等函式。因此在 Helm Chart 中,尤其是需要控制 YAML 縮排時,通常會優先使用
include。
with — 縮小作用域當模板裡頻繁存取同一組巢狀資料時,例如:
.Values.image.repository
.Values.image.tag
.Values.image.pullPolicy
可以使用 with 縮小作用域,讓模板更簡潔。
改寫前:
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
改寫後:
{{- with .Values.image }}
image: "{{ .repository }}:{{ .tag }}"
imagePullPolicy: {{ .pullPolicy }}
{{- end }}
進入 with .Values.image 之後,. 會改成指向 .Values.image,所以原本:
.Values.image.repository
就可以簡化成:
.repository
⚠️ 注意
with會改變.的作用域在
with區塊中,.不再代表原本的 root context。如果這時候需要存取最上層的物件,例如 Release 名稱,可以使用
$:{{- with .Values.image }} release: {{ $.Release.Name }} image: "{{ .repository }}:{{ .tag }}" {{- end }}可以把
$理解成回到模板最上層 context 的入口。
toYaml — 輸出結構化資料當你想把 values.yaml 裡的一整段結構直接輸出成 YAML 時,可以使用 toYaml。
常見例子就是 resources。
在 values.yaml 加入:
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
在模板中引用:
resources:
{{- toYaml .Values.resources | nindent 2 }}
toYaml 會把 .Values.resources 轉成 YAML 格式,再搭配 nindent 2 處理換行與縮排。
渲染後會變成:
resources:
limits:
cpu: 200m
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
這樣就不用在模板裡一個欄位一個欄位手動對應,values.yaml 裡的結構也能比較完整地保留下來。
💡
toYaml常和nindent一起使用
toYaml負責把資料轉成 YAML,nindent則負責把輸出的內容放到正確的縮排層級。
實務上通常會有 dev、staging、prod 等不同環境,而每個環境的參數可能不一樣。
Helm 可以透過 -f 指定額外的 values 檔案,覆寫 Chart 內建的 values.yaml。
# 開發環境
vim my-chart/values-dev.yaml
replicaCount: 1
image:
tag: "latest"
# 正式環境
vim my-chart/values-prod.yaml
replicaCount: 5
image:
tag: "1.27"
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 200m
memory: 256Mi
# 先移除 Day 21 的 Release(如果還存在)
helm uninstall my-release
# 開發環境
helm install my-release-dev ./my-chart \
-f my-chart/values-dev.yaml
# 正式環境
helm install my-release-prod ./my-chart \
-f my-chart/values-prod.yaml

這樣同一份 Chart,就可以搭配不同的 values 檔案部署到不同環境。
⚠️ Release 名稱
在同一個 Namespace 中,Release Name 必須唯一。
如果同一個 Release 還存在,又再次執行:
helm install my-release ./my-chart就會因名稱已被使用而安裝失敗。
實務上不同環境通常會使用不同的 Release Name,也常會部署到不同的 Namespace,例如
dev、staging、prod。
💡 Values 覆寫優先順序
簡化來看,可以記成:
values.yaml—— Chart 內建的預設值-f values-dev.yaml—— 額外指定的 values 檔案--set replicaCount=10—— 命令列直接覆寫後面的設定會覆蓋前面相同的 Key。
因此通常會把:
values.yaml:放通用的預設值values-dev.yaml/values-prod.yaml:只放各環境不同的設定這樣就不用為每個環境複製一整份 Chart。
if 做可選資源不是每個環境都需要 Ingress 或 HPA。
透過 if 判斷 values 裡的開關,就能決定某個 Kubernetes 資源是否要被產生。
vim my-chart/values.yaml
在最後加入:
ingress:
enabled: false
host: myapp.example.com

vim my-chart/templates/ingress.yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "my-chart.fullname" . }}
labels:
{{- include "my-chart.labels" . | nindent 4 }}
spec:
rules:
- host: {{ .Values.ingress.host }}
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: {{ include "my-chart.fullname" . }}
port:
number: {{ .Values.service.port }}
{{- end }}
當:
ingress:
enabled: false
這份 Ingress Template 就不會產生任何 Kubernetes Manifest。
預設:
helm template my-release ./my-chart
因為:
ingress.enabled: false
所以不會看到 Ingress 資源。
如果想開啟 Ingress:
helm template my-release ./my-chart \
--set ingress.enabled=true
這次渲染結果就會多出一個 Ingress。
⚠️ 注意
ingress.enabled=true只代表 Helm 會建立 Ingress Resource。要讓 Ingress 實際處理外部流量,叢集裡還需要有對應的 Ingress Controller。
完成所有模板修改後,再跑一次驗證流程:
# 1. 檢查 Chart
helm lint ./my-chart
# 2. 本地渲染,確認最終 YAML
helm template my-release ./my-chart
# 3. 實際部署
helm upgrade --install my-release ./my-chart
其中:
helm upgrade --install
代表:
upgrade
install
很適合在反覆修改 Chart 時使用。


my-release-nginx
app、chart、release
ingress.enabled: false 時,是否不會產生 Ingresshelm template 的輸出中看到 Ingress Resource例如:
helm template my-release ./my-chart \
--set ingress.enabled=true
這時就應該會多出 Ingress Manifest。
| 函式 | 用途 | 範例 |
|---|---|---|
default |
值為空時提供預設值 | default 80 .Values.port |
printf |
格式化字串 | printf "%s-%s" .Release.Name .Chart.Name |
toYaml |
將資料轉成 YAML 格式 | toYaml .Values.resources |
indent |
為每一行加上縮排 | include "tpl" . | indent 4 |
nindent |
先換行,再為每一行加上縮排 | include "tpl" . | nindent 4 |
quote |
將值包成雙引號字串 | quote .Values.image.tag |
upper / lower |
字串大小寫轉換 | upper .Values.env |
trimSuffix |
移除字串尾端指定內容 | trimSuffix "-" $name |
required |
值為空時中止渲染並顯示錯誤 | required "需要 image.tag" .Values.image.tag |
今天我們把 Day 21 的精簡模板進一步整理成更容易維護的版本,回顧重點:
| 學到的東西 | 一句話總結 |
|---|---|
_helpers.tpl |
用 define 定義共用模板,再透過 include 重複引用,集中管理命名與 Labels |
include vs template |
實務上通常優先使用 include,因為可以搭配 Pipeline、indent、nindent 等函式 |
with |
縮小作用域,簡化巢狀資料存取,但要注意 . 的指向會改變 |
toYaml |
將結構化資料轉成 YAML,再搭配 nindent 放進正確的縮排層級 |
| 多環境 values | 使用 -f values-prod.yaml 等檔案覆寫預設值,讓同一份 Chart 套用到不同環境 |
功能開關(if) |
透過 enabled: true/false 控制某些 Kubernetes 資源是否產生 |
到這裡,我們已經從「會建立 Helm Chart」,進一步學會如何讓 Chart 減少重複、提高彈性,也更容易維護。
下一篇,我們會進一步學習 Helm Repository 與 Chart 依賴管理,了解如何讓自己的 Chart 引用其他 Chart,並管理更複雜的應用組合!