iT邦幫忙

2026 iThome 鐵人賽

DAY 21
0

前言

Day 20 我們學會了使用別人提供的 Helm Chart —— 包含搜尋、安裝、升級、回滾與移除等基本操作。

但如果今天想把自己開發的應用程式也打包成 Chart,讓團隊成員只需要一行指令就能部署呢?

今天我們就來從零打造一個 Helm Chart,內容包含:

  1. 建立 Chart 骨架 —— 使用 helm create 產生基本結構,了解每個檔案的用途
  2. Chart.yaml —— 認識 Chart 的基本資訊
  3. Go Template 語法入門 —— 學會 Helm 模板最常用的寫法
  4. 實戰練習 —— 手寫 Deployment + Service 模板,部署一個 Nginx
  5. 驗證流程 —— helm linthelm templatehelm install
  6. 打包與分享 —— 使用 helm package 將 Chart 打包
  7. 常用指令速查表 —— 整理本篇會用到的 Helm 指令

以下操作皆在 master 節點執行。


一、用 helm create 建立 Chart 骨架

不需要自己一個一個建立檔案,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 名稱、版本等基本資訊

二、Chart.yaml — Chart 的身分證

打開 my-chart/Chart.yaml

cat my-chart/Chart.yaml

可以看到 Chart 的基本資訊

https://ithelp.ithome.com.tw/upload/images/20260820/20181928kzSLKK48Y4.png

每個欄位的意思:

欄位 說明 什麼時候要改?
apiVersion Chart API 版本;Helm 3 使用 v2 通常不用改
name Chart 名稱 建立 Chart 時決定
description Chart 的簡短說明 可以依專案用途修改
type applicationlibrary 一般可部署的應用維持 application
version Chart 本身的版本 模板、values 或 Chart 內容有變更時遞增
appVersion 應用程式的版本資訊 應用程式版本升級時更新

⚠️ version vs appVersion

  • version:代表 Helm Chart 本身的版本
  • appVersion:代表 Chart 所部署應用程式的版本資訊
  • 兩者是獨立的,不需要相同

要注意:appVersion 本身只是資訊欄位,不會自動修改 Container Image Tag;是否使用它,要看 Chart Template 怎麼寫。


三、Go Template 模板語法入門

Helm 的模板語法是以 Go Template 為基礎。

核心概念很簡單:凡是寫在 {{ ... }} 裡的內容,都會在 Helm 渲染 Chart 時被解析並替換。

3.1 讀取參數

語法 來源 範例
{{ .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

3.2 條件判斷(if)

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 或其他可選資源。

3.3 迴圈(range)

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 或其他重複設定。

3.4 預設值(default)

Helm Template 可以使用 default,在參數沒有值時提供一個備用值:

{{ .Values.service.port | default 80 }}

如果 .Values.service.port 沒有設定或是空值,就會使用:

80

💡 關於空白控制

Helm Template 中的 - 可以用來移除多餘的空白或換行。

例如:

{{- if .Values.ingress.enabled }}
...
{{- end }}

{{- 會移除左側的空白,實務上常用在 ifrange 等區塊,避免渲染後出現太多空行。


四、實戰:從零手寫 Chart 部署 Nginx

helm create 預設產生的模板功能很完整,但對剛開始學 Helm Template 來說會稍微複雜。

這裡我們先把 templates/ 目錄中的預設模板清空,接著從最精簡的版本開始自己建立。

rm -rf my-chart/templates/*

Step 1:建立 values.yaml

helm create 預設產生的 values.yaml 內容比較完整,包含 imagePullSecretsserviceAccountingressautoscaling 等許多設定。

這次練習只需要最基本的參數,因此我們直接重新建立一份精簡版:

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 出現語法錯誤,可以先檢查 {{ ... }} 是否被改動。

Step 2:建立 Deployment 模板

新增 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

Step 3:建立 Service 模板

新增 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 資源。


五、驗證三部曲:lint → template → install

寫完模板後,不要急著直接 install

建議養成下面三個步驟的驗證流程:

  1. helm lint:先檢查 Chart 結構與模板是否有明顯問題
  2. helm template:確認實際渲染出的 Kubernetes YAML
  3. helm install:最後再真正部署到叢集

Step 1:lint — 先檢查 Chart 有沒有問題

helm lint ./my-chart

helm lint 會檢查 Chart 是否符合基本規範,例如:

  • Chart.yaml 是否正確
  • Template 是否有語法問題
  • Values 是否能正常帶入模板
  • 是否存在一些常見的 Chart 結構問題

如果檢查通過,通常會看到類似:

https://ithelp.ithome.com.tw/upload/images/20260820/20181928zf3E80egWP.png

不過要注意,helm lint 通過不代表部署後一定能正常運作,它主要是做 Chart 與 Template 層級的檢查。

下一步還要用 helm template 看實際渲染結果。

Step 2:template — 確認渲染結果

helm template my-release ./my-chart

https://ithelp.ithome.com.tw/upload/images/20260820/201819289nGGpu6JUf.png

這個指令會把 Helm Template 渲染成完整的 Kubernetes YAML 並輸出到終端,但不會真的部署到叢集

可以用來檢查:

  • values.yaml 的參數有沒有正確帶入
  • {{ .Release.Name }} 是否被正確替換
  • YAML 的縮排與結構是否正確
  • 最終產生的 Deployment、Service 是否符合預期

例如這次可以看到:

metadata:
  name: my-release-nginx

以及:

replicas: 2

代表 .Release.Name.Values.replicaCount 都已經正確渲染。

💡 helm lint 的差別

helm lint 偏向檢查 Chart 是否有明顯的格式或模板問題;

helm template 則是直接把最終會產生的 YAML 顯示出來,方便你在部署前再次確認。

Step 3:install — 實際部署到叢集

前面確認 Chart 與渲染結果都沒問題後,就可以正式安裝:

helm install my-release ./my-chart

如果安裝成功,可以看到類似:

https://ithelp.ithome.com.tw/upload/images/20260820/20181928IiyQ9ty9MH.png

接著確認部署結果:

# 確認 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

💡 把這三步變成習慣

  1. helm lint —— 檢查 Chart 結構與模板是否有明顯問題
  2. helm template —— 在本機渲染 YAML,確認最終內容
  3. helm install + kubectl get —— 實際部署到叢集並確認資源狀態

可以簡單記成:

lint → 看有沒有問題 → template → 看會產生什麼 → install → 看實際跑得怎麼樣

補充:試試覆寫參數

安裝完成後,如果想調整參數,可以搭配 helm upgrade--set

helm upgrade my-release ./my-chart --set replicaCount=5

這個指令會把 replicaCount 覆寫成 5,並建立新的 Release Revision。

執行成功後,可以看到:

https://ithelp.ithome.com.tw/upload/images/20260820/20181928Hq8f5p0gfw.png

驗證:

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

https://ithelp.ithome.com.tw/upload/images/20260820/2018192845PQ1XupHx.png


六、打包與分享

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 Repository:GitHub Pages、ChartMuseum 等
  • OCI Registry:例如支援 OCI 的 Container Registry

⚠️ 打包前記得確認 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 linthelm templatehelm install,部署後再搭配 kubectl get 確認結果
helm package 將 Chart 打包成 .tgz,方便保存、分享或上傳到 Repository / OCI Registry

到這裡,你已經會「使用別人的 Chart」,也會「建立自己的 Chart」了。

不過目前我們的模板還很精簡。如果想加入可選的 Ingress、環境變數注入、多環境切換,或共用名稱與 Label 等設計,就需要更進階的 Helm Template 技巧。

下一篇我們來學 Helm 進階模板與 _helpers.tpl —— 讓 Chart 更有彈性,也更容易維護!


參考資源


上一篇
Day 20|Helm — Kubernetes 的套件管理工具
下一篇
Day 22|Helm 進階模板與 `_helpers.tpl` — 讓 Chart 更靈活、更好維護
系列文
從零到 CKA:30 天掌握 Kubernetes 核心觀念與實作23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言