上一個章節中,我們介紹了如何透過減少縮排與使用 _helpers.tpl
來讓 Helm 模板更加簡潔易讀。這一章將進一步回顧並實作一些 Helm Template 常用的 Go 語法與函數,幫助我們在撰寫 Chart 時更有效率地處理各種情境。
Helm 提供了超過 60 種以上的內建函數,來源主要分為兩類:
你也可以透過 Helm 官方文件的 Template Function List 查閱完整清單;若想進一步理解函數的詳細運作,可以直接參考 Go Template 語言或 Sprig 函數庫 的原始文件。
本章將分享幾個我在實務專案中經常使用且特別實用的函數,這些函數能夠大幅簡化模板邏輯,讓 Helm Chart 更加精簡、易於維護。
接下來,我們將逐一介紹並提供範例:
以下是依照你提供的說明,針對 coalesce、join & splitList/split、ternary、adler32sum 四個函數所做的完整示範與解說,包含實務情境、範例 YAML 片段,以及如何在 Helm Chart 中運用它們來簡化模板。
coalesce
– 多來源參數的預設值選擇用途:
coalesce
會依序檢查傳入的參數,回傳第一個非空值。
這在我們有多個可能來源的設定時非常實用,例如:
values.yaml
中的明確設定值_helpers.tpl
中計算後的結果- 預設值 fallback
某個服務的 replicas
可能來自三個來源:
values.yaml
內設定_helpers.tpl
動態計算1
_helpers.tpl
{{/*
根據服務類型計算預設 replicas
*/}}
{{- define "mychart.calculateReplicas" -}}
{{- if eq .Values.serviceType "high-availability" -}}
3
{{- else -}}
2
{{- end -}}
{{- end }}
deployment.yaml
spec:
replicas: {{ coalesce .Values.replicas (include "mychart.calculateReplicas" .) 1 }}
values.yaml 設定 |
渲染結果 |
---|---|
replicas: 5 |
replicas: 5 |
無設定,serviceType: high-availability |
replicas: 3 |
完全未設定 | replicas: 1 |
好處:
避免冗長的if/else
判斷,且可保證值一定存在。
join
+ splitList
/ split
– 多層清單轉字串用途:
splitList
/split
將字串切割為清單join
將清單合併回字串搭配使用時,可以:
- 將複雜的設定展平成一條字串
- 自動控制分隔符號,不會多出尾端逗號
假設我們的 values.yaml
定義了多個標籤與子層級設定:
tags: "env=prod,team=data,region=asia"
ports:
- 8080
- 9090
configmap.yaml
data:
TAGS: "{{ join ";" (splitList "," .Values.tags) }}"
data:
TAGS: "env=prod;team=data;region=asia"
在多個 port 設定下,自動生成 containerPort
並確保最後一個元素後沒有逗號。
deployment.yaml
containers:
- name: myapp
ports:
{{- range $index, $port := .Values.ports }}
- containerPort: {{ $port }}
{{- end }}
假設我們有一個複雜的輸入,格式如下:
hosts: "kafka1:9092,kafka2:9092,kafka3:9092"
我們想要轉成 Kafka bootstrap 連線字串:
kafka1:9092;kafka2:9092;kafka3:9092
configmap.yaml
data:
KAFKA_BOOTSTRAP: "{{ join ";" (splitList "," .Values.hosts) }}"
data:
KAFKA_BOOTSTRAP: "kafka1:9092;kafka2:9092;kafka3:9092"
好處:
不需要額外手動處理尾端分隔符號,模板更簡潔。
ternary
– 三元運算簡化 if/else
用途:
使用ternary
可以在一行中完成if/else
判斷,讓模板更加簡短。
{{ ternary <真值> <假值> <條件> }}
根據 env
判斷是否開啟 debug 模式。
values.yaml
env: prod
configmap.yaml
data:
DEBUG_MODE: "{{ ternary "true" "false" (eq .Values.env "dev") }}"
env 設定 | 渲染結果 |
---|---|
dev |
DEBUG_MODE: "true" |
prod |
DEBUG_MODE: "false" |
adler32sum
– 生成唯一短碼用途:
當需要根據服務名稱或命名空間生成唯一 ID 時,adler32sum
提供一個快速的哈希演算法,適合用於:
- Kafka Broker ID
- StatefulSet Pod 唯一識別
- Job 名稱避免重複
我們想要針對 Release.Name
生成一個唯一數字 ID。
statefulset.yaml
metadata:
name: {{ .Release.Name }}-{{ adler32sum .Release.Name }}
如果 Release 名稱是 kafka-prod
:
metadata:
name: kafka-prod-2874896061
Kafka Broker 需要唯一的 broker.id
,我們可以直接使用 adler32sum
確保不同 Release 有不同 ID:
env:
- name: BROKER_ID
value: "{{ adler32sum (printf "%s-%s" .Release.Name .Values.kafka.brokerName) }}"
以下是一個結合上述所有函數的完整範例,展示如何在實務中同時運用。
values.yaml
replicas: ""
serviceType: high-availability
tags: "env=prod,team=data,region=asia"
hosts: "kafka1:9092,kafka2:9092,kafka3:9092"
env: dev
kafka:
brokerName: brokerA
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-{{ adler32sum .Release.Name }}
spec:
replicas: {{ coalesce .Values.replicas (include "mychart.calculateReplicas" .) 1 }}
template:
spec:
containers:
- name: myapp
env:
- name: DEBUG_MODE
value: "{{ ternary "true" "false" (eq .Values.env "dev") }}"
- name: TAGS
value: "{{ join ";" (splitList "," .Values.tags) }}"
- name: KAFKA_BOOTSTRAP
value: "{{ join ";" (splitList "," .Values.hosts) }}"
- name: BROKER_ID
value: "{{ adler32sum (printf "%s-%s" .Release.Name .Values.kafka.brokerName) }}"
metadata:
name: myrelease-2874896061
spec:
replicas: 3
template:
spec:
containers:
- name: myapp
env:
- name: DEBUG_MODE
value: "true"
- name: TAGS
value: "env=prod;team=data;region=asia"
- name: KAFKA_BOOTSTRAP
value: "kafka1:9092;kafka2:9092;kafka3:9092"
- name: BROKER_ID
value: "1770260294"
函數 | 核心價值 |
---|---|
coalesce |
依序檢查並回傳第一個非空值,簡化多來源 fallback 邏輯 |
join + splitList |
將複雜清單或字串展平成乾淨格式,避免手動處理尾端分隔符號 |
ternary |
簡化 if/else ,讓模板更簡潔 |
adler32sum |
生成唯一短碼,常用於 ID 或名稱避免衝突 |
透過這些函數,可以讓 Helm Template 更加模組化、可讀性更高,同時降低錯誤發生的機率,適合應用在大型服務部署與自動化流程中。
以上分享了一些我在日常工作中時常使用的函數,這些函數能夠讓模板更簡潔、可讀性更高,也能減少在專案中處理複雜邏輯時的心智負擔。接下來,我想分享一些我自己在工作中遵循的最佳實踐。
⚠️ 注意:這些方法不一定完全適合每個團隊,但可以作為參考依據,讓你思考如何優化自己的 Helm Chart。
Helm 官方文件提供了完整的 Chart 撰寫建議與原則,主要分為三個章節:
values.yaml
中的參數如果你的團隊剛開始接觸 Helm,這三個章節是必讀的內容,能幫助建立一致且可維護的 Chart 基礎。
除了官方的原則,我也整理了一些個人經驗,特別是針對 模板結構與可讀性 的最佳實踐。
在實際專案中,模板經過不斷迭代與功能擴充後,常會遇到以下問題:
if/else
判斷式以下是我常用的兩項策略。
_helpers.tpl
收斂判斷邏輯Helm 提供 _helpers.tpl
作為自訂函數集中管理的檔案。
我建議將複雜或重複的判斷邏輯全部收納到 _helpers.tpl
中,模板本身只負責呼叫結果。
判斷條件直接寫在模板內,導致程式碼冗長、可讀性差:
metadata:
labels:
{{- if eq .Values.env "prod" }}
environment: production
{{- else if eq .Values.env "dev" }}
environment: development
{{- else }}
environment: staging
{{- end }}
將判斷式集中在 _helpers.tpl
中:
_helpers.tpl
{{- define "mychart.environmentLabel" -}}
{{- if eq .Values.env "prod" }}production
{{- else if eq .Values.env "dev" }}development
{{- else }}staging
{{- end }}
{{- end }}
deployment.yaml
metadata:
labels:
environment: {{ include "mychart.environmentLabel" . }}
好處:
- 模板內只保留最終渲染的 YAML 結構
- 判斷邏輯統一管理,便於日後修改
在 Helm Template 中,你可以使用 {{- $var := ... -}}
來定義變數。
我的習慣是在每個模板的最上方區塊統一準備好渲染過程中會使用的變數,並確保變數命名清楚、語意明確。
{{- $fullName := include "mychart.fullname" . -}}
{{- $replicas := coalesce .Values.replicas (include "mychart.calculateReplicas" .) 1 -}}
{{- $envLabel := include "mychart.environmentLabel" . -}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ $fullName }}
labels:
environment: {{ $envLabel }}
spec:
replicas: {{ $replicas }}
好處:
- 變數集中,一眼即可看出此模板需要哪些輸入
- 在下方核心 YAML 區塊,看到的內容與最終渲染結果幾乎一致
- Debug 或修改時,降低錯誤風險
撰寫 Helm Template 時,應兼顧功能完整性與可維護性:
_helpers.tpl
收斂複雜邏輯,避免模板本體過於混亂除了函數與模板結構的設計外,我認為理解 Helm 的運作本質,也能夠很好的幫助各位進行Helm Chart的設計,Helm template的本質上是文字整理與渲染流程:
values.yaml
作為輸入但重點在於:值的結構與型別會深刻影響模板邏輯。特別要注意 values.yaml 中輸入的是 map、list 還是 slice——這會直接左右你如何迭代、取值與判斷:
map:適合具命名的鍵值對,便於條件判斷與鍵名存取
list:適合順序資料,例如 ports、env 等
slice:常見於由 splitList 等轉換產生的集合,需要確認型別使用方式
若在設計階段沒有把資料結構設計好,後續模板會充斥型別判斷與轉換邏輯,降低可讀性。這也是為何把型別處理與資料準備封裝到 _helpers.tpl
非常重要——它能讓主模板更貼近結果,專注於「要輸出的 YAML」而非處理細節。
在本章中,我們深入探討了 Helm Template 中常見且實用的函數,並透過實務案例展示如何在複雜的專案中保持模板簡潔、乾淨,提升維護效率。
函數應用回顧
coalesce
:簡化多來源參數選擇,避免冗長的 if/else
join
+ splitList
:輕鬆進行清單與字串轉換,減少尾端符號錯誤ternary
:一行完成三元判斷,讓模板邏輯更直觀adler32sum
:快速生成唯一短碼,避免名稱或 ID 衝突模板最佳實踐
_helpers.tpl
:保持主模板純淨,專注於 YAML 結構理解 Helm 的本質
values.yaml
輸入轉成 Kubernetes YAML。map
、list
、slice
的選擇會影響模板迭代、判斷與結構設計。總結一句話:
你可以簡單地把 Helm 看作是文字整理工具,也可以嚴謹地將它當作需要型別控制與邏輯設計的程式工具;兩種思維的取捨,決定了 Chart 的整潔度與維護成本。
在掌握了 Helm 函數應用與模板設計的基本功後,下一步,我們將 瀏覽 Bitnami Helm Charts。
這些 Chart 以結構清晰、命名一致、可擴展性高聞名,能為我們在實務專案中的 template 結構設計 與 values.yaml 規劃 提供寶貴參考。
感謝各位閱讀,我們明天見!