
身為一個常常在 Kubernetes 叢集上部署各種服務的工程師,Helm 絕對是我工具箱裡不可或缺的利器。之前我們聊過 Helm Chart 的基本概念,今天就來把 Helm Chart 的目錄結構和模板語法徹底拆解一遍,讓你日後自己寫 Chart 時能夠得心應手。
Helm Chart 目錄結構
要建立一個全新的 Chart,只需要一行指令:
helm create mychart
產生出來的目錄結構如下:
| 路徑 | 用途說明 |
|---|---|
mychart/Chart.yaml | Chart 的元資料檔案(名稱、版本等) |
mychart/values.yaml | 預設的組態設定值 |
mychart/charts/ | 存放相依的子 Chart |
mychart/templates/ | Kubernetes 資源的模板檔案 |
templates/deployment.yaml | Deployment 資源模板 |
templates/_helpers.tpl | 可重複使用的模板片段 |
templates/hpa.yaml | HPA 水平自動擴展模板 |
templates/ingress.yaml | Ingress 入口規則模板 |
templates/service.yaml | Service 服務模板 |
templates/serviceaccount.yaml | ServiceAccount 模板 |
templates/NOTES.txt | 安裝後的使用說明 |
templates/tests/ | 測試用的模板 |
Chart.yaml 長什麼樣?
這是 Chart 的身分證,記載了所有基本資訊:
apiVersion: v2 # Chart API 版本(必填)
name: mychart # Chart 名稱(必填)
version: 0.1.0 # Chart 版本號(必填)
description: 我的第一個 Chart # 描述(選填)
appVersion: "1.0" # 應用程式版本(選填)
values.yaml 預設組態
這份檔案定義了模板中會用到的變數預設值,在模板裡面用 {{ .Values.replicaCount }} 這樣的語法來引用:
replicaCount: 1
image:
repository: nginx
tag: "1.19"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
templates/ 與 charts/ 目錄
templates/ 裡面放的是 Kubernetes 資源的模板文件,Helm 引擎會把 values 注入模板後,產生實際可以部署的 YAML 清單。
charts/ 則是用來放相依的子 Chart,可以透過 helm dependency 指令來管理這些依賴關係。
模板語法核心觀念
模板指令與跳脫
{{ }}雙大括號裡面的就是模板指令- 如果內容本身包含大括號,需要用反引號跳脫處理
註解寫法
| 位置 | 註解方式 |
|---|---|
values.yaml | 使用 # 號 |
templates/ 目錄下的模板 | 使用 {{/* 註解內容 */}} |
內建物件一覽
Helm 提供了好幾個內建物件,讓你在模板裡可以靈活取用各種資訊。
Release 物件
描述當次部署實例的資訊:
| 物件 | 說明 |
|---|---|
Release.Name | Release 名稱 |
Release.Time | Release 時間 |
Release.Namespace | 所在的命名空間 |
Release.Service | Release 服務名稱 |
Release.Revision | 修訂版本號(從 1 開始遞增) |
Release.IsUpgrade | 是否為升級或回滾操作 |
Release.IsInstall | 是否為首次安裝 |
Chart 物件與 Values 物件
Chart 物件對應 Chart.yaml 裡的內容,例如 {{ .Chart.Name }}、{{ .Chart.Version }}。
Values 物件的資料來源有四個,優先順序由低到高:
| 優先順序 | 來源 |
|---|---|
| 1 | 子 Chart 的 values.yaml |
| 2 | 父 Chart 的 values.yaml |
| 3 | -f 或 --values 指定的 YAML 檔 |
| 4 | --set 指定的鍵值對參數 |
Files 物件
用來存取 Chart 中非特殊用途的檔案:
| 函數 | 用途 |
|---|---|
Files.Get | 透過檔名取得檔案 |
Files.Lines | 逐行讀取檔案 |
Files.AsSecrets | 以 BASE64 編碼回傳 |
Files.Glob | 以 pattern 比對取得檔案列表 |
Files.AsConfig | 以 YAML 格式回傳 |
Capabilities 物件
取得 Kubernetes 叢集相關資訊:
{{ .Capabilities.KubeVersion }} # K8s 版本
{{ .Capabilities.APIVersions.Has "batch/v1" }} # 是否支援某 API 版本

模板函數大全
Helm 內建了豐富的模板函數,以下整理成表格方便查閱:
| 函數 | 功能說明 |
|---|---|
quote | 自動加上雙引號 "" |
squote | 自動加上單引號 '' |
title | 首字母大寫 |
upper | 全部轉大寫 |
lower | 全部轉小寫 |
empty | 判斷值是否為空 |
repeat N | 將值重複 N 次 |
indent N | 縮排 N 個空格 |
nindent N | 換行 + 縮排 N 個空格 |
default "xxx" | 設定預設值 |
split "/" | 以指定字元分割 |
toYaml | 將 List 轉成 YAML 格式 |
b64enc / b64dec | BASE64 編碼 / 解碼 |
print | 組合字串 |
printf | 格式化字串 |
trim | 移除首尾空白 |
trimAll | 移除指定字元 |
contains | 判斷是否包含子字串 |
cat | 用空格合併多個字串 |
tpl | 將 Values 中的模板指令進行渲染 |
管道(Pipeline)
跟 Linux 的管道 | 概念一樣,可以串接函數處理值:
k8s: {{ .Values.course.k8s | quote }}
這行的意思是:從 Values 讀取 course.k8s 的值,再透過 quote 函數加上雙引號。
流程控制語法
if / else 條件判斷
{{- if eq .Values.xxx "參數" }}
xxxx
{{- else if xxxx }}
yyyy
{{- else }}
zzzz
{{- end }}
支援的比較運算子:eq(等於)、ne(不等於)、lt(小於)、gt(大於)、and、or、not。
with 限定作用域
{{- with .Values.course }}
k8s: {{ .k8s | upper | quote }}
python: {{ .python | repeat 3 | quote }}
release: {{ .Release.Name }}
{{- end }}
在 with 區塊內,. 的作用域會限縮到指定的物件上。
range 迴圈
方式一:遍歷 Map
# values.yaml
env:
enable: true
items:
name1: value1
name2: value2
# templates/deployment.yaml
containers:
- name: xxx
{{- if .Values.env.enable }}
env:
{{- range $name, $value := .Values.env.items }}
- name: {{ $name }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
方式二:遍歷 List
# values.yaml
env:
- name: xxx1
value: xxx1
- name: xxx2
value: xxx2
# templates/deployment.yaml
containers:
- name: xxx
env:
{{- range .Values.env }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
模板變數
用 :=(海象運算子)來宣告變數:
{{- $releaseName := .Release.Name }}
實際範例:
# 用 split 分割路徑,取第二個元素
{{- $service := (.Template.Name | split "/")._2 }}
# 用 index 從 map 中取值
{{- $config := index .Values.config $service }}
命名模板(Named Templates)
這是 Helm 裡面實現程式碼重用的關鍵機制。
重點觀念
- 模板名稱是全域的
- 通常定義在
_helpers.tpl檔案中 templates/下以_開頭的檔案和NOTES.txt不會被當作資源清單_開頭的檔案可以被其他模板引用
define 定義模板
{{/* 產生基本的 labels 標籤 */}}
{{- define "mychart.labels" }}
labels:
generator: helm
date: {{ now | htmlDate }}
{{- end }}
template vs include
| 特性 | template | include |
|---|---|---|
| 類型 | 動作(action) | 函數(function) |
| 管道支援 | 不支援 | 支援 |
| 縮排控制 | 無法控制 | 可搭配 indent 函數 |
# template 用法
{{- template "mychart.labels" }}
# include 用法(推薦,可控制縮排)
{{- include "mychart.labels" . | indent 2 }}
實務上我幾乎都用 include,因為能搭配 indent 或 nindent 來精確控制 YAML 的縮排,避免格式錯亂的問題。
YAML 錨點(Anchor)
這其實是 YAML 本身的功能,但在 Helm 模板中也很實用:
# 定義錨點
anchors:
pod_template: &pod_template
apiVersion: v1
kind: Pod
metadata:
labels:
app: demo
# 引用錨點
apiVersion: v1
kind: Pod
metadata:
name: demo_pod
<<: *pod_template
用 & 定義錨點,用 * 引用錨點,搭配 <<: 可以合併鍵值。這在有大量重複設定時特別好用。
結語
Helm Chart 的模板語法乍看之下有點複雜,但只要理解了內建物件、模板函數、流程控制和命名模板這幾個核心概念,基本上就能應付大多數的場景了。
我自己的經驗是:先從修改既有的 Chart 開始練習,等熟悉語法後再嘗試從零開始建立自己的 Chart,這樣學習曲線會平緩很多。如果在 debug 的時候遇到問題,記得善用 helm template 指令來預覽渲染結果,這招真的超級實用!

發佈留言