Day 20 我們學會了使用別人提供的 Helm Chart —— 包含搜尋、安裝、升級、回滾與移除等基本操作。
但如果今天想把自己開發的應用程式也打包成 Chart,讓團隊成員只需要一行指令就能部署呢?
今天我們就來從零打造一個 Helm Chart,內容包含:
helm create 產生基本結構,了解每個檔案的用途helm lint → helm template → helm install
helm package 將 Chart 打包以下操作皆在 master 節點執行。
不需要自己一個一個建立檔案,Helm 提供了建立 Chart 骨架的指令:
helm create my-chart
執行後,Helm 會自動產生一組基本的 Chart 目錄與範例模板。
實際產生的檔案可能會因 Helm 版本而略有不同,常見結構如下:
my-chart/
├── Chart.yaml # Chart 的基本資訊
├── values.yaml # 預設參數,使用者可以覆寫
├── charts/ # 放 Chart dependencies
├── templates/ # Kubernetes YAML 模板
│ ├── _helpers.tpl # 共用的模板片段
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ ├── hpa.yaml
│ ├── ingress.yaml
│ ├── NOTES.txt # 安裝完成後顯示的提示訊息
│ └── tests/
│ └── test-connection.yaml
└── .helmignore # 打包 Chart 時要忽略的檔案
💡 用比喻理解 Chart 結構
可以把 Helm Chart 想成一份「填空題考卷」:
templates/:放的是題目,也就是帶有{{ ... }}的 Kubernetes YAML 模板values.yaml:像是答案表,提供模板需要的參數值- Helm:負責把 values 套用到模板中,渲染出完整的 Kubernetes YAML
Chart.yaml:像是這份考卷的封面,記錄 Chart 名稱、版本等基本資訊
打開 my-chart/Chart.yaml:
cat my-chart/Chart.yaml
可以看到 Chart 的基本資訊

每個欄位的意思:
| 欄位 | 說明 | 什麼時候要改? |
|---|---|---|
apiVersion |
Chart API 版本;Helm 3 使用 v2 |
通常不用改 |
name |
Chart 名稱 | 建立 Chart 時決定 |
description |
Chart 的簡短說明 | 可以依專案用途修改 |
type |
application 或 library |
一般可部署的應用維持 application |
version |
Chart 本身的版本 | 模板、values 或 Chart 內容有變更時遞增 |
appVersion |
應用程式的版本資訊 | 應用程式版本升級時更新 |
⚠️
versionvsappVersion
version:代表 Helm Chart 本身的版本appVersion:代表 Chart 所部署應用程式的版本資訊- 兩者是獨立的,不需要相同
要注意:
appVersion本身只是資訊欄位,不會自動修改 Container Image Tag;是否使用它,要看 Chart Template 怎麼寫。
Helm 的模板語法是以 Go Template 為基礎。
核心概念很簡單:凡是寫在 {{ ... }} 裡的內容,都會在 Helm 渲染 Chart 時被解析並替換。
| 語法 | 來源 | 範例 |
|---|---|---|
{{ .Values.xxx }} |
從 values.yaml 或使用者提供的 values 讀取 |
{{ .Values.replicaCount }} → 2 |
{{ .Release.Name }} |
目前 Release 的名稱 | my-release |
{{ .Chart.Name }} |
Chart.yaml 裡的 name |
my-chart |
{{ include "tpl" . }} |
引用 _helpers.tpl 中定義的共用模板 |
常用來產生名稱、Label 等 |
例如 values.yaml:
replicaCount: 2
在模板中寫:
spec:
replicas: {{ .Values.replicaCount }}
Helm 渲染後就會變成:
spec:
replicas: 2
Helm Template 可以透過 if 判斷是否要產生某一段 YAML。
例如:
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
# ...
{{- end }}
如果 values.yaml 裡設定:
ingress:
enabled: false
那麼這整段 Ingress YAML 就不會被渲染出來。
這種寫法很適合拿來做功能開關,例如決定是否建立 Ingress、HPA 或其他可選資源。
Helm Template 可以使用 range 來遍歷 List,動態產生多筆內容。
例如:
{{- range .Values.env }}
- name: {{ .name }}
value: {{ .value }}
{{- end }}
搭配 values.yaml:
env:
- name: APP_ENV
value: production
- name: LOG_LEVEL
value: info
渲染後會變成:
- name: APP_ENV
value: production
- name: LOG_LEVEL
value: info
這種寫法適合用來動態產生多筆環境變數、Port 或其他重複設定。
Helm Template 可以使用 default,在參數沒有值時提供一個備用值:
{{ .Values.service.port | default 80 }}
如果 .Values.service.port 沒有設定或是空值,就會使用:
80
💡 關於空白控制
Helm Template 中的
-可以用來移除多餘的空白或換行。例如:
{{- if .Values.ingress.enabled }} ... {{- end }}
{{-會移除左側的空白,實務上常用在if、range等區塊,避免渲染後出現太多空行。
helm create 預設產生的模板功能很完整,但對剛開始學 Helm Template 來說會稍微複雜。
這裡我們先把 templates/ 目錄中的預設模板清空,接著從最精簡的版本開始自己建立。
rm -rf my-chart/templates/*
helm create 預設產生的 values.yaml 內容比較完整,包含 imagePullSecrets、serviceAccount、ingress、autoscaling 等許多設定。
這次練習只需要最基本的參數,因此我們直接重新建立一份精簡版:
rm my-chart/values.yaml
vim my-chart/values.yaml
接著填入:
replicaCount: 2
image:
repository: nginx
tag: "1.27"
pullPolicy: IfNotPresent
service:
type: ClusterIP
port: 80
containerPort: 80
⚠️ 複製 Helm Template 時注意格式
如果直接從網頁或筆記工具複製 Helm Template,
{{ ... }}有時可能因格式轉換而跑版,例如變成帶有多餘引號的形式。正確格式應該像這樣:
{{ .Release.Name }} {{ .Values.image.repository }}大括號與變數之間可以有空格,但不要出現額外的
""。如果複製後 Helm 出現語法錯誤,可以先檢查
{{ ... }}是否被改動。
新增 my-chart/templates/deployment.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-nginx
labels:
app: {{ .Release.Name }}-nginx
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ .Release.Name }}-nginx
template:
metadata:
labels:
app: {{ .Release.Name }}-nginx
spec:
containers:
- name: nginx
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.containerPort }}
protocol: TCP
這份 Deployment 模板會從 values.yaml 讀取副本數、Image、Pull Policy 與 Container Port。
{{ .Release.Name }}:取得安裝時指定的 Release 名稱{{ .Values.replicaCount }}:取得 Pod 副本數{{ .Values.image.repository }}:取得 Image 名稱{{ .Values.image.tag }}:取得 Image Tag{{ .Values.image.pullPolicy }}:取得 Image Pull Policy{{ .Values.containerPort }}:取得 Container Port新增 my-chart/templates/service.yaml:
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-nginx
spec:
type: {{ .Values.service.type }}
selector:
app: {{ .Release.Name }}-nginx
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.containerPort }}
protocol: TCP
💡 觀察 Deployment 與 Service 的對應關係
Service 的:
selector: app: {{ .Release.Name }}-nginx會對應 Deployment Pod Template 裡的:
labels: app: {{ .Release.Name }}-nginx因此 Service 可以找到這個 Deployment 建立出的 Pod。
例如執行:
helm install my-nginx ./my-chart
{{ .Release.Name }}會被替換成my-nginx,因此資源名稱會變成:my-nginx-nginx使用不同的 Release 名稱安裝同一個 Chart,就能產生不同名稱的 Kubernetes 資源。
寫完模板後,不要急著直接 install。
建議養成下面三個步驟的驗證流程:
helm lint:先檢查 Chart 結構與模板是否有明顯問題helm template:確認實際渲染出的 Kubernetes YAMLhelm install:最後再真正部署到叢集helm lint ./my-chart
helm lint 會檢查 Chart 是否符合基本規範,例如:
Chart.yaml 是否正確如果檢查通過,通常會看到類似:

不過要注意,helm lint 通過不代表部署後一定能正常運作,它主要是做 Chart 與 Template 層級的檢查。
下一步還要用 helm template 看實際渲染結果。
helm template my-release ./my-chart

這個指令會把 Helm Template 渲染成完整的 Kubernetes YAML 並輸出到終端,但不會真的部署到叢集。
可以用來檢查:
values.yaml 的參數有沒有正確帶入{{ .Release.Name }} 是否被正確替換例如這次可以看到:
metadata:
name: my-release-nginx
以及:
replicas: 2
代表 .Release.Name 與 .Values.replicaCount 都已經正確渲染。
💡 和
helm lint的差別
helm lint偏向檢查 Chart 是否有明顯的格式或模板問題;
helm template則是直接把最終會產生的 YAML 顯示出來,方便你在部署前再次確認。
前面確認 Chart 與渲染結果都沒問題後,就可以正式安裝:
helm install my-release ./my-chart
如果安裝成功,可以看到類似:

接著確認部署結果:
# 確認 Release 是否存在
helm list
# 查看這個 Release 建立的 Kubernetes 資源
kubectl get all -l app=my-release-nginx
# 查看這個 Release 使用的完整 values
helm get values my-release --all
# 查看這個 Release 產生的 Kubernetes Manifest
helm get manifest my-release
💡 把這三步變成習慣
helm lint—— 檢查 Chart 結構與模板是否有明顯問題helm template—— 在本機渲染 YAML,確認最終內容helm install+kubectl get—— 實際部署到叢集並確認資源狀態可以簡單記成:
lint → 看有沒有問題 → template → 看會產生什麼 → install → 看實際跑得怎麼樣
安裝完成後,如果想調整參數,可以搭配 helm upgrade 與 --set:
helm upgrade my-release ./my-chart --set replicaCount=5
這個指令會把 replicaCount 覆寫成 5,並建立新的 Release Revision。
執行成功後,可以看到:

驗證:
kubectl get pods -l app=my-release-nginx
# 應該會看到 5 個 Pod

Chart 開發完成後,可以使用 helm package 打包成 .tgz 檔案,方便保存與分享:
helm package ./my-chart
如果 Chart.yaml 中設定:
name: my-chart
version: 0.1.0
就會產生:
my-chart-0.1.0.tgz
打包完成後,可以直接安裝:
helm install my-release ./my-chart-0.1.0.tgz
也可以將 Chart 分享到其他地方,例如:
⚠️ 打包前記得確認 Chart 版本
helm package會讀取Chart.yaml裡的version,並把它放進產生的檔名中。例如:
version: 0.2.0打包後會產生:
my-chart-0.2.0.tgz當 Chart 的模板、values 或其他 Chart 內容有變更時,應該依版本管理規則更新
version,方便追蹤不同版本的 Chart。
| 指令 | 用途 |
|---|---|
helm create <name> |
建立 Chart 骨架 |
helm lint <chart-path> |
檢查 Chart 結構與模板 |
helm template <release> <chart> |
本地渲染模板,不部署 |
helm install <release> <chart> |
安裝 Chart 到叢集 |
helm upgrade <release> <chart> |
升級已安裝的 Release |
helm package <chart-path> |
打包成 .tgz |
helm get values <release> --all |
查看 Release 使用的完整 values |
helm get manifest <release> |
查看 Release 產生的 Kubernetes Manifest |
今天我們從零打造了一個 Helm Chart,回顧重點:
| 重點 | 總結 |
|---|---|
| Chart 骨架 | helm create 快速建立基本結構,templates/ 放模板、values.yaml 放參數、Chart.yaml 放 Chart 基本資訊 |
| Chart.yaml | version 是 Chart 版本,appVersion 是應用程式版本,兩者獨立管理 |
| Go Template | {{ .Values.xxx }} 讀取參數、if 做條件判斷、range 做迴圈、default 提供預設值 |
| values.yaml | 集中管理可調整參數,也可以透過 --set 或 -f 覆寫 |
| 驗證三部曲 | helm lint → helm template → helm install,部署後再搭配 kubectl get 確認結果 |
| helm package | 將 Chart 打包成 .tgz,方便保存、分享或上傳到 Repository / OCI Registry |
到這裡,你已經會「使用別人的 Chart」,也會「建立自己的 Chart」了。
不過目前我們的模板還很精簡。如果想加入可選的 Ingress、環境變數注入、多環境切換,或共用名稱與 Label 等設計,就需要更進階的 Helm Template 技巧。
下一篇我們來學 Helm 進階模板與 _helpers.tpl —— 讓 Chart 更有彈性,也更容易維護!