Kubernetes 生態系統的快速發展使得應用程式部署的複雜度持續提升,單一應用程式可能涉及數十個相互關聯的資源定義,包括 Deployment、Service、ConfigMap、Secret 等多種物件類型。手動管理這些 YAML 配置檔案不僅容易出錯,更難以實現版本控制與環境間的一致性部署。Helm 作為 Kubernetes 的套件管理工具,透過 Chart 的概念將應用程式的所有資源定義封裝為可重複使用的套件,提供範本化機制處理環境差異,並支援版本管理與依賴關係處理。
然而,要充分發揮 Helm 的價值,需要深入理解其設計理念與技術細節。Chart 的結構設計影響可維護性與重用性,不當的組織方式導致配置混亂且難以擴展。範本函式與管線的運用需要平衡靈活性與可讀性,過度複雜的範本邏輯增加維護成本。生命週期鉤子提供在部署流程特定時點執行操作的機制,但需要審慎設計以避免影響部署穩定性。測試策略的完整性決定 Chart 的品質保證水準,從靜態語法檢查到動態部署驗證,每個環節都需要適當的工具與方法。
Chart 的分發與共享需要建立儲存庫基礎設施,選擇適當的託管方案並配置存取控制機制。CI/CD 管線的整合自動化了 Chart 的建構、測試與發布流程,確保每次變更都經過完整驗證。GitOps 實踐將 Chart 的配置納入版本控制系統,實現聲明式的應用程式管理模式。Operator 模式的結合則將 Chart 的靜態配置與動態運算邏輯相結合,實現更智慧的應用生命週期管理。安全性考量貫穿整個 Chart 開發與部署流程,從簽章驗證確保 Chart 完整性,到 RBAC 配置限制資源存取,每個環節都需要遵循安全最佳實務。
本文將系統性地探討 Helm Chart 的進階應用技術,從基礎的 Chart 結構設計到複雜的 Operator 整合,從本地開發測試到生產環境部署,提供完整的技術指南與實務建議。透過深入理解這些技術細節,讀者能夠建構高品質、安全且易於維護的 Kubernetes 應用程式套件。
Helm Chart 的結構設計與元資料管理
Helm Chart 作為 Kubernetes 應用程式的封裝單元,其結構設計遵循特定的目錄規範與檔案組織原則。一個標準的 Chart 包含數個核心組件,每個組件承擔特定的功能角色。Chart.yaml 檔案定義 Chart 的元資料,包括名稱、版本、描述、維護者資訊等識別資訊。values.yaml 檔案提供預設的配置參數,使用者可以透過覆寫這些值來客製化部署行為。templates 目錄存放 Kubernetes 資源的範本檔案,透過 Go 範本語法實現動態配置生成。charts 目錄包含 Chart 依賴的其他 Chart,支援多層次的應用組合。
Chart.yaml 的元資料設計需要考慮多個面向。版本號碼遵循語意化版本規範,主版本號變更表示不相容的 API 修改,次版本號變更表示向後相容的功能新增,修訂號變更則代表錯誤修復。依賴關係的聲明透過 dependencies 欄位實現,指定依賴 Chart 的名稱、版本約束與儲存庫位置。關鍵字與類型標籤協助使用者在 Chart 儲存庫中搜尋與分類 Chart。維護者資訊與專案連結提供聯繫管道與文件參考。
# Chart.yaml - Helm Chart 元資料定義檔案
# 定義 Chart 的基本資訊、版本控制與依賴關係
# API 版本:Helm 3 使用 v2
apiVersion: v2
# Chart 名稱:必須符合 DNS 標籤規範
name: web-application
# Chart 描述:簡要說明 Chart 的功能與用途
description: 企業級 Web 應用程式 Helm Chart,支援高可用性部署
# Chart 類型:application 或 library
# application:可獨立部署的應用程式
# library:提供給其他 Chart 使用的函式庫
type: application
# Chart 版本:遵循語意化版本規範
# 格式:主版本號.次版本號.修訂號
version: 1.2.3
# 應用程式版本:Chart 封裝的應用程式版本
# 此欄位為資訊性質,不影響 Chart 行為
appVersion: "2.5.1"
# 關鍵字:協助 Chart 分類與搜尋
keywords:
- web
- application
- microservices
- high-availability
# 首頁:專案官方網站或文件站點
home: https://example.com/web-application
# 原始碼儲存庫:專案原始碼位置
sources:
- https://github.com/example/web-application
# 維護者資訊:Chart 維護人員聯繫方式
maintainers:
- name: "DevOps Team"
email: "devops@example.com"
url: "https://example.com/team/devops"
# Chart 圖示:顯示於 Chart 儲存庫介面
# 建議使用 SVG 格式以支援縮放
icon: https://example.com/assets/chart-icon.svg
# 依賴關係:聲明此 Chart 依賴的其他 Chart
dependencies:
# Redis 快取服務
- name: redis
version: "17.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: redis.enabled
tags:
- cache
import-values:
- child: auth.password
parent: redis.password
# PostgreSQL 資料庫服務
- name: postgresql
version: "12.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
tags:
- database
# 監控堆疊(可選依賴)
- name: prometheus
version: "15.x.x"
repository: "https://prometheus-community.github.io/helm-charts"
condition: monitoring.prometheus.enabled
tags:
- monitoring
# 註解:額外的元資料,可被工具讀取
annotations:
# Artifact Hub 分類
artifacthub.io/category: "web-applications"
# 變更日誌連結
artifacthub.io/changes: |
- kind: added
description: 新增 Redis 快取支援
- kind: changed
description: 更新 PostgreSQL 至 12.x 版本
- kind: fixed
description: 修正 Ingress 配置錯誤
# 授權資訊
artifacthub.io/license: "Apache-2.0"
# 安全報告聯繫方式
artifacthub.io/securityReportCreatedAt: "2024-01-15T10:30:00Z"
# 已棄用標記(若 Chart 不再維護)
# deprecated: true
# 最小 Kubernetes 版本要求
kubeVersion: ">=1.24.0"
Chart.lock 檔案在依賴管理中扮演重要角色。當執行 helm dependency update 命令時,Helm 會解析 Chart.yaml 中聲明的依賴關係,從指定的儲存庫下載對應版本的 Chart,並生成 Chart.lock 檔案記錄實際使用的精確版本。這個機制確保了依賴的可重現性,即使依賴 Chart 發布了新版本,只要 Chart.lock 存在,helm dependency build 命令會使用鎖定的版本重建 charts 目錄。這種設計類似於其他語言生態系統的依賴鎖定機制,例如 Node.js 的 package-lock.json 或 Python 的 Pipfile.lock。
# Chart.lock - 依賴版本鎖定檔案
# 記錄實際使用的依賴 Chart 版本,確保可重現性
dependencies:
# Redis 依賴的精確版本
- name: redis
repository: https://charts.bitnami.com/bitnami
version: 17.11.3
digest: sha256:a1b2c3d4e5f6...
# PostgreSQL 依賴的精確版本
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 12.5.8
digest: sha256:f6e5d4c3b2a1...
# 生成時間戳記
generated: "2024-01-20T14:30:00.123456789Z"
範本函式與管線的實務運用
Helm 範本引擎基於 Go 的 text/template 套件,提供豐富的內建函式與管線操作能力。範本函式可分為數個類別,包括字串處理、資料轉換、流程控制、檔案操作等。字串處理函式如 upper、lower、title 用於調整文字大小寫,quote 函式將字串包裹於引號中確保 YAML 語法正確性。資料轉換函式如 toYaml、toJson 將 Go 資料結構序列化為特定格式,便於嵌入至資源定義中。流程控制函式如 if、range、with 實現條件判斷與迴圈遍歷。
管線操作符號允許將函式呼叫鏈接起來,前一個函式的輸出作為後一個函式的輸入。這種機制類似於 Unix 管線,提供簡潔且可讀的資料處理方式。例如,將字串轉換為大寫後再包裹引號的操作可以寫為 .Values.name | upper | quote。管線的右結合特性允許從左至右依序處理資料,每個階段的轉換都清晰可見。
Sprig 函式庫擴展了 Helm 的範本能力,提供超過百個額外函式。日期時間處理函式如 now、date 可用於生成時間戳記或格式化日期。加密函式如 sha256sum、bcrypt 支援雜湊計算與密碼處理。集合操作函式如 list、dict 提供資料結構建構能力。這些函式大幅提升了範本的表達能力,但也需要謹慎使用以維持範本的可讀性。
# Deployment 範本範例
# 展示範本函式與管線的實務運用
apiVersion: apps/v1
kind: Deployment
metadata:
# 使用 include 函式引用命名範本
# 範本定義於 _helpers.tpl 檔案
name: {{ include "web-app.fullname" . }}
# 命名空間繼承自 Release 物件
namespace: {{ .Release.Namespace }}
labels:
# 使用標準標籤範本確保一致性
{{- include "web-app.labels" . | nindent 4 }}
# 自訂標籤:應用程式版本
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
# 自訂標籤:部署時間戳記
deployment.timestamp: {{ now | date "2006-01-02T15:04:05Z07:00" | quote }}
annotations:
# 配置雜湊:用於觸發滾動更新
# 當 ConfigMap 或 Secret 內容變更時自動重新部署
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
spec:
# 副本數:支援條件判斷
{{- if .Values.autoscaling.enabled }}
# 啟用自動擴展時忽略副本數設定
{{- else }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "web-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "web-app.selectorLabels" . | nindent 8 }}
annotations:
# Prometheus 抓取配置
prometheus.io/scrape: "true"
prometheus.io/port: {{ .Values.service.port | quote }}
prometheus.io/path: "/metrics"
spec:
# 服務帳號:支援條件建立
{{- if .Values.serviceAccount.create }}
serviceAccountName: {{ include "web-app.serviceAccountName" . }}
{{- end }}
# 映像拉取密鑰
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
# 安全性上下文
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
# 映像:組合儲存庫、名稱與標籤
image: {{ printf "%s/%s:%s" .Values.image.repository .Values.image.name (.Values.image.tag | default .Chart.AppVersion) }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
# 環境變數:支援多種來源
env:
# 直接定義的環境變數
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
# 從 ConfigMap 引用的環境變數
{{- if .Values.envFrom.configMapRef }}
- name: CONFIG_SOURCE
valueFrom:
configMapKeyRef:
name: {{ include "web-app.fullname" . }}-config
key: source
{{- end }}
# 從 Secret 引用的環境變數
{{- if .Values.envFrom.secretRef }}
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "web-app.fullname" . }}-secret
key: db-password
{{- end }}
# 健康檢查探針
{{- if .Values.livenessProbe.enabled }}
livenessProbe:
httpGet:
path: {{ .Values.livenessProbe.path }}
port: http
initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
{{- end }}
{{- if .Values.readinessProbe.enabled }}
readinessProbe:
httpGet:
path: {{ .Values.readinessProbe.path }}
port: http
initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
successThreshold: {{ .Values.readinessProbe.successThreshold }}
{{- end }}
# 資源限制
{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
# 容器安全性上下文
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
# 掛載卷
{{- if or .Values.persistence.enabled .Values.extraVolumeMounts }}
volumeMounts:
{{- if .Values.persistence.enabled }}
- name: data
mountPath: {{ .Values.persistence.mountPath }}
{{- if .Values.persistence.subPath }}
subPath: {{ .Values.persistence.subPath }}
{{- end }}
{{- end }}
{{- with .Values.extraVolumeMounts }}
{{- toYaml . | nindent 12 }}
{{- end }}
{{- end }}
# 卷定義
{{- if or .Values.persistence.enabled .Values.extraVolumes }}
volumes:
{{- if .Values.persistence.enabled }}
- name: data
{{- if .Values.persistence.existingClaim }}
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim }}
{{- else }}
persistentVolumeClaim:
claimName: {{ include "web-app.fullname" . }}-data
{{- end }}
{{- end }}
{{- with .Values.extraVolumes }}
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
# 節點選擇器
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
# 親和性規則
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
# 容忍度規則
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
命名範本(Named Templates)提供程式碼重用機制,透過 define 動作定義可被 include 或 template 函式引用的範本片段。慣例上,命名範本定義於 _helpers.tpl 檔案,檔案名稱前綴底線表示其不會被渲染為獨立的 Kubernetes 資源。命名範本通常用於生成重複使用的標籤集合、資源名稱、或複雜的條件邏輯。include 函式返回範本渲染結果的字串,可以進一步透過管線處理,而 template 函式直接輸出渲染結果,不支援管線操作。
# _helpers.tpl - 命名範本定義檔案
# 提供可重用的範本片段
{{/*
生成完整的資源名稱
結合 Release 名稱與 Chart 名稱
*/}}
{{- define "web-app.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
生成標準標籤集合
符合 Kubernetes 推薦標籤規範
*/}}
{{- define "web-app.labels" -}}
helm.sh/chart: {{ include "web-app.chart" . }}
{{ include "web-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
生成選擇器標籤
用於 Service 與 Deployment 的匹配
*/}}
{{- define "web-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "web-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
生成 ServiceAccount 名稱
支援自訂或自動生成
*/}}
{{- define "web-app.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "web-app.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
@startuml
!define PLANTUML_FORMAT svg
!theme _none_
skinparam dpi auto
skinparam shadowing false
skinparam linetype ortho
skinparam roundcorner 5
skinparam defaultFontName "Microsoft JhengHei UI"
skinparam defaultFontSize 16
skinparam minClassWidth 100
title Helm 範本渲染流程
start
:讀取 Chart 結構;
note right
Chart.yaml
values.yaml
templates/
end note
:解析 values.yaml;
:載入預設值;
:合併使用者提供的值;
note right
--set 命令列參數
--values 自訂檔案
end note
partition "範本渲染" {
:遍歷 templates 目錄;
repeat
:讀取範本檔案;
:解析範本語法;
if (是否為命名範本?) then (是)
:註冊範本定義;
else (否)
:執行範本函式;
:處理管線操作;
:替換變數參照;
:渲染完整 YAML;
:驗證 YAML 語法;
endif
repeat while (是否還有範本?) is (是)
}
:產生 Kubernetes 資源清單;
:輸出渲染結果;
stop
@enduml生命週期鉤子的應用場景
Helm 提供生命週期鉤子機制,允許在 Chart 安裝、升級、刪除、回滾等操作的特定時點執行額外的 Kubernetes 資源。鉤子透過資源的 annotations 欄位聲明,使用 helm.sh/hook 註解指定鉤子類型。支援的鉤子類型包括 pre-install、post-install、pre-upgrade、post-upgrade、pre-delete、post-delete、pre-rollback、post-rollback 等。每種鉤子類型對應特定的執行時點,例如 pre-install 在 Chart 安裝前執行,post-upgrade 在升級完成後執行。
鉤子的執行順序透過 helm.sh/hook-weight 註解控制,權重值為整數,按升序依序執行。相同權重的鉤子執行順序不確定,建議為需要特定順序的鉤子分配不同權重。鉤子的刪除策略透過 helm.sh/hook-delete-policy 註解配置,支援 before-hook-creation、hook-succeeded、hook-failed 等策略。before-hook-creation 策略在新鉤子執行前刪除舊鉤子資源,hook-succeeded 在鉤子執行成功後刪除,hook-failed 則在失敗後刪除。
# Pre-install 鉤子:資料庫初始化 Job
# 在應用程式安裝前建立必要的資料庫結構
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "web-app.fullname" . }}-db-init
labels:
{{- include "web-app.labels" . | nindent 4 }}
annotations:
# 鉤子類型:安裝前執行
"helm.sh/hook": pre-install
# 鉤子權重:控制執行順序
# 數值越小越早執行
"helm.sh/hook-weight": "-5"
# 刪除策略:成功後刪除,失敗時保留以供偵錯
"helm.sh/hook-delete-policy": hook-succeeded
spec:
# 不自動重試失敗的鉤子
backoffLimit: 0
template:
metadata:
labels:
{{- include "web-app.labels" . | nindent 8 }}
spec:
# 鉤子完成後不自動重啟
restartPolicy: Never
containers:
- name: db-init
image: {{ .Values.database.initImage }}
env:
# 資料庫連接資訊
- name: DB_HOST
value: {{ .Values.database.host | quote }}
- name: DB_PORT
value: {{ .Values.database.port | quote }}
- name: DB_NAME
value: {{ .Values.database.name | quote }}
- name: DB_USER
valueFrom:
secretKeyRef:
name: {{ include "web-app.fullname" . }}-db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ include "web-app.fullname" . }}-db-secret
key: password
command:
- /bin/sh
- -c
- |
# 等待資料庫服務就緒
until pg_isready -h $DB_HOST -p $DB_PORT -U $DB_USER; do
echo "等待資料庫啟動..."
sleep 2
done
# 執行資料庫初始化腳本
psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -f /scripts/init.sql
echo "資料庫初始化完成"
volumeMounts:
- name: init-scripts
mountPath: /scripts
readOnly: true
volumes:
- name: init-scripts
configMap:
name: {{ include "web-app.fullname" . }}-db-init-scripts
# Post-upgrade 鉤子:資料庫遷移 Job
# 在應用程式升級後執行資料庫結構變更
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "web-app.fullname" . }}-db-migrate-{{ .Release.Revision }}
labels:
{{- include "web-app.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": post-upgrade
"helm.sh/hook-weight": "0"
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: db-migrate
image: {{ .Values.database.migrateImage }}
env:
- name: DB_CONNECTION_STRING
valueFrom:
secretKeyRef:
name: {{ include "web-app.fullname" . }}-db-secret
key: connection-string
# 遷移版本:與應用程式版本對應
- name: TARGET_VERSION
value: {{ .Chart.AppVersion | quote }}
command:
- /migrations/migrate
- up
- --database=$(DB_CONNECTION_STRING)
- --path=/migrations/scripts
- --target=$(TARGET_VERSION)
volumeMounts:
- name: migration-scripts
mountPath: /migrations/scripts
readOnly: true
volumes:
- name: migration-scripts
configMap:
name: {{ include "web-app.fullname" . }}-db-migrations
# Pre-delete 鉤子:資料備份 Job
# 在 Chart 刪除前備份重要資料
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "web-app.fullname" . }}-backup-{{ now | date "20060102-150405" }}
labels:
{{- include "web-app.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": pre-delete
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": hook-succeeded
spec:
template:
spec:
restartPolicy: Never
containers:
- name: backup
image: {{ .Values.backup.image }}
env:
- name: BACKUP_DESTINATION
value: {{ .Values.backup.destination | quote }}
- name: BACKUP_TIMESTAMP
value: {{ now | date "20060102-150405" | quote }}
command:
- /bin/sh
- -c
- |
# 建立備份目錄
mkdir -p /backup
# 備份資料庫
pg_dump $DB_CONNECTION_STRING > /backup/database-${BACKUP_TIMESTAMP}.sql
# 備份持久化資料
tar -czf /backup/data-${BACKUP_TIMESTAMP}.tar.gz /data
# 上傳至遠端儲存
rclone copy /backup/ ${BACKUP_DESTINATION}
echo "備份完成"
volumeMounts:
- name: data
mountPath: /data
readOnly: true
volumes:
- name: data
persistentVolumeClaim:
claimName: {{ include "web-app.fullname" . }}-data
鉤子的實務應用需要考慮多個面向。鉤子失敗會導致整個操作失敗,因此需要確保鉤子邏輯的健壯性與冪等性。冪等性意味著多次執行相同鉤子產生相同結果,這對於處理重試場景特別重要。鉤子執行的超時時間需要根據任務複雜度設定,過短的超時可能導致未完成的鉤子被強制終止。鉤子資源的命名需要包含唯一識別符,例如 Release 版本號或時間戳記,避免與先前執行的鉤子資源衝突。
Chart 測試方法論與工具鏈
Helm Chart 的測試可分為靜態驗證與動態測試兩大類別。靜態驗證不需要實際的 Kubernetes 叢集,透過分析 Chart 檔案結構與範本語法檢測潛在問題。動態測試則需要在實際或模擬的 Kubernetes 環境中部署 Chart,驗證其執行時期行為。完整的測試策略結合兩種方法,在開發早期透過靜態驗證快速發現基本錯誤,在整合階段透過動態測試驗證實際部署效果。
helm lint 命令執行 Chart 的靜態分析,檢查 Chart.yaml 的必要欄位、範本檔案的語法正確性、values.yaml 的結構合理性等。該命令會輸出警告與錯誤訊息,協助開發者識別配置問題。yamllint 工具提供更嚴格的 YAML 語法檢查,可以配置規則集強制特定的編碼風格,例如縮排寬度、行尾字元、鍵值對齊等。kubeval 工具驗證渲染後的 Kubernetes 資源定義是否符合 API 規範,確保資源能夠被 Kubernetes 接受。
#!/usr/bin/env bash
# Helm Chart 完整測試腳本
# 整合靜態驗證與動態測試
set -euo pipefail
# 變數定義
readonly CHART_DIR="./charts/web-app"
readonly NAMESPACE="test-$(date +%s)"
readonly RELEASE_NAME="test-release"
# 函式:執行靜態驗證
static_validation() {
echo "=========================================="
echo "執行靜態驗證"
echo "=========================================="
# Helm lint:Chart 結構檢查
echo "執行 Helm lint..."
helm lint "$CHART_DIR" --strict
# yamllint:YAML 語法檢查
echo "執行 yamllint..."
yamllint -c .yamllint.yaml "$CHART_DIR"
# 範本渲染測試
echo "執行範本渲染測試..."
helm template "$RELEASE_NAME" "$CHART_DIR" \
--debug \
--namespace "$NAMESPACE" \
> /tmp/rendered-manifests.yaml
# kubeval:Kubernetes API 驗證
echo "執行 kubeval 驗證..."
kubeval --strict /tmp/rendered-manifests.yaml
echo "靜態驗證完成"
}
# 函式:執行動態測試
dynamic_testing() {
echo "=========================================="
echo "執行動態測試"
echo "=========================================="
# 建立測試命名空間
echo "建立測試命名空間 $NAMESPACE..."
kubectl create namespace "$NAMESPACE"
# 安裝 Chart(乾跑模式)
echo "執行乾跑安裝..."
helm install "$RELEASE_NAME" "$CHART_DIR" \
--namespace "$NAMESPACE" \
--dry-run \
--debug
# 實際安裝 Chart
echo "執行實際安裝..."
helm install "$RELEASE_NAME" "$CHART_DIR" \
--namespace "$NAMESPACE" \
--wait \
--timeout 5m
# 執行 Helm test
echo "執行 Helm test..."
helm test "$RELEASE_NAME" \
--namespace "$NAMESPACE" \
--logs
# 驗證 Pod 狀態
echo "驗證 Pod 狀態..."
kubectl get pods \
--namespace "$NAMESPACE" \
--selector "app.kubernetes.io/instance=$RELEASE_NAME"
# 測試升級流程
echo "測試升級流程..."
helm upgrade "$RELEASE_NAME" "$CHART_DIR" \
--namespace "$NAMESPACE" \
--set replicaCount=3 \
--wait \
--timeout 5m
# 測試回滾功能
echo "測試回滾功能..."
helm rollback "$RELEASE_NAME" 1 \
--namespace "$NAMESPACE" \
--wait
echo "動態測試完成"
}
# 函式:清理測試資源
cleanup() {
echo "=========================================="
echo "清理測試資源"
echo "=========================================="
# 解除安裝 Release
helm uninstall "$RELEASE_NAME" \
--namespace "$NAMESPACE" || true
# 刪除命名空間
kubectl delete namespace "$NAMESPACE" --wait=false || true
echo "清理完成"
}
# 主程式流程
main() {
echo "開始 Helm Chart 測試"
# 執行靜態驗證
static_validation
# 執行動態測試
dynamic_testing
# 清理資源
cleanup
echo "=========================================="
echo "所有測試通過"
echo "=========================================="
}
# 錯誤處理:確保清理資源
trap cleanup EXIT ERR
# 執行主程式
main "$@"
Chart Testing 工具針對在單一儲存庫中管理多個 Chart 的場景最佳化,支援自動偵測變更的 Chart 並僅測試受影響的部分。該工具整合 lint、安裝、測試等多個階段,提供完整的測試工作流程。配置檔案允許客製化測試行為,例如指定測試值檔案、設定超時時間、配置目標 Kubernetes 版本等。ct lint 命令執行 Chart 的 lint 檢查與 YAML 驗證,ct install 命令在測試叢集中實際安裝 Chart 並執行 Helm test。
# .ct.yaml - Chart Testing 配置檔案
# Chart 目錄
chart-dirs:
- charts
# Chart 儲存庫
chart-repos:
- bitnami=https://charts.bitnami.com/bitnami
# 目標 Kubernetes 版本
kubernetes-version: v1.27.0
# Helm 額外參數
helm-extra-args: --timeout 5m
# 驗證維護者資訊
check-version-increment: true
# 測試值檔案目錄
test-ct-values-file: ci/test-values.yaml
本文深入探討了 Helm Chart 的進階應用技術,從 Chart 結構的設計原則到範本函式的實務運用,從生命週期鉤子的應用場景到完整的測試方法論。透過系統性的技術說明與完整的程式碼範例,展示了如何建構高品質、可維護且安全的 Kubernetes 應用程式套件。Helm 作為 Kubernetes 生態系統的核心工具,其價值不僅在於簡化部署流程,更在於提供標準化的應用程式封裝與分發機制。掌握這些進階技術,能夠協助開發團隊建立成熟的 Kubernetes 應用程式管理體系,在確保部署一致性的同時維持彈性與可擴展性。持續最佳化 Chart 設計,根據實際需求調整範本複雜度與測試策略,是確保 Helm 實踐長期價值的關鍵。