Skip to content
Published on

Helmテンプレートエンジン深層分析: Goテンプレート、Sprig、名前付きテンプレート

Authors

1. Goテンプレートの内部動作

1.1 パーシング段階

Helmのテンプレートエンジンはtext/templateをベースとしています。テンプレート処理はパーシング実行の2段階に分かれます。

テンプレートテキスト → レキサー → トークンストリーム → パーサー → AST

1.2 実行段階

実行段階ではASTを走査しながらデータコンテキスト(ドット.)を適用します:

# パイプライン: 左の出力が右の入力に渡される
name: { { .Values.name | lower | trunc 63 | trimSuffix "-" } }

1.3 空白制御

{{- include "my-chart.labels" . | nindent 4 }}
#^ 左の空白/改行を除去

{{ include "my-chart.labels" . | nindent 4 -}}
#                                           ^ 右の空白/改行を除去

2. Sprigライブラリ関数

2.1 文字列関数

upper: {{ "hello" | upper }}          # HELLO
lower: {{ "HELLO" | lower }}          # hello
title: {{ "hello world" | title }}    # Hello World
trim: {{ "  hello  " | trim }}        # hello
trunc: {{ "hello" | trunc 3 }}        # hel
contains: {{ contains "lo" "hello" }} # true
replace: {{ "hello world" | replace " " "-" }}  # hello-world
snakecase: {{ "HelloWorld" | snakecase }}        # hello_world
kebabcase: {{ "HelloWorld" | kebabcase }}        # hello-world
randAlphaNum: {{ randAlphaNum 10 }}

2.2 数学関数

add: {{ add 1 2 }}    # 3
sub: {{ sub 10 3 }}   # 7
mul: {{ mul 2 3 }}    # 6
max: {{ max 1 2 3 }}  # 3
ceil: {{ ceil 1.1 }}  # 2
floor: {{ floor 1.9 }}# 1

2.3 暗号化関数

sha256sum: {{ "hello" | sha256sum }}
b64enc: {{ "hello" | b64enc }}
uuid: {{ uuidv4 }}

2.4 リスト関数

list: { { list "a" "b" "c" } }
first: { { first (list "a" "b" "c") } } # a
append: { { append (list "a" "b") "c" } } # [a b c]
has: { { has "b" (list "a" "b" "c") } } # true
sortAlpha: { { sortAlpha (list "c" "a" "b") } } # [a b c]

2.5 辞書関数

{{- $myDict := dict "key1" "value1" "key2" "value2" }}
get: {{ get $myDict "key1" }}          # value1
hasKey: {{ hasKey $myDict "key1" }}     # true
keys: {{ keys $myDict }}                # [key1 key2]

3. 名前付きテンプレート

3.1 defineとtemplate

# templates/_helpers.tpl
{{- define "my-chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{- define "my-chart.fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}

3.2 template vs include

# template: 結果を直接出力(パイプライン使用不可)
{{ template "my-chart.name" . }}

# include: 結果を文字列として返す(パイプライン使用可能)
{{ include "my-chart.labels" . | nindent 4 }}

includeの使用が推奨されます。 パイプラインによる後処理が可能なためです。

3.3 標準ヘルパーパターン

{{- define "my-chart.labels" -}}
helm.sh/chart: {{ include "my-chart.chart" . }}
{{ include "my-chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{- define "my-chart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

4. フロー制御

4.1 if/else

{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "my-chart.fullname" . }}
{{- end }}

{{- if eq .Values.service.type "NodePort" }}
  nodePort: {{ .Values.service.nodePort }}
{{- else if eq .Values.service.type "LoadBalancer" }}
  loadBalancerIP: {{ .Values.service.loadBalancerIP }}
{{- end }}

4.2 with

{{- with .Values.nodeSelector }}
nodeSelector:
  {{- toYaml . | nindent 2 }}
{{- end }}

# withブロック内で上位スコープにアクセスする場合は$を使用
{{- with .Values.container }}
  name: {{ $.Chart.Name }}
  image: {{ .image }}
{{- end }}

4.3 range

{{- range .Values.extraEnvVars }}
- name: {{ .name }}
  value: {{ .value | quote }}
{{- end }}

{{- range $key, $value := .Values.configData }}
{{ $key }}: {{ $value | quote }}
{{- end }}

{{- range until 5 }}
- replica-{{ . }}
{{- end }}

5. 高度なテンプレートパターン

5.1 tpl関数

# values.yaml
configTemplate: |
  server.name={{ .Release.Name }}

# templates/configmap.yaml
data:
  config.properties: |
    {{ tpl .Values.configTemplate . | nindent 4 }}

5.2 lookup関数

{{- $secret := lookup "v1" "Secret" .Release.Namespace "my-secret" }}
{{- if $secret }}
password: {{ index $secret.data "password" }}
{{- else }}
password: {{ randAlphaNum 16 | b64enc }}
{{- end }}

6. ライブラリチャート

ライブラリチャート(type: library)は自身のリソースをレンダリングせず、名前付きテンプレートのみ提供します:

apiVersion: v2
name: my-library
type: library
version: 1.0.0

メリット: 共通テンプレートロジックの共有、標準ラベル/アノテーションの一元管理、DRY原則の遵守。


7. デバッグ

helm template my-release ./my-chart
helm template my-release ./my-chart -s templates/deployment.yaml --debug
helm lint ./my-chart --strict

8. まとめ

Helmテンプレートエンジンは単純な文字列置換を超えた強力なプログラミングモデルを提供します:

  1. Goテンプレートベース: パーシング-実行の2段階パイプラインアーキテクチャ
  2. Sprigライブラリ: 100以上のユーティリティ関数
  3. 名前付きテンプレート: define/includeによる再利用可能なテンプレートモジュール化
  4. フロー制御: if/with/rangeによる条件付き・反復レンダリング
  5. ライブラリチャート: 共通ロジックの集中管理と共有

次の記事ではHelmリリースの全ライフサイクル(install、upgrade、rollback)を分析します。