フロー制御
制御構造(テンプレート用語では「アクション」と呼ばれます)は、テンプレートの作成者であるあなたに、テンプレートの生成フローを制御する機能を提供します。 Helmのテンプレート言語は、以下の制御構造を提供します。
- 条件付きブロックを作成するための
if
/else
- スコープを指定するための
with
- 「for each」スタイルのループを提供する
range
これらに加えて、名前付きテンプレートセグメントを宣言および使用するためのいくつかのアクションが提供されています。
define
は、テンプレート内に新しい名前付きテンプレートを宣言します。template
は、名前付きテンプレートをインポートします。block
は、特別な種類の埋め込み可能なテンプレート領域を宣言します。
このセクションでは、if
、with
、およびrange
について説明します。 その他については、このガイドの後半にある「名前付きテンプレート」セクションで説明します。
If/Else
最初に説明する制御構造は、テンプレートにテキストブロックを条件付きで含めるためのものです。 これはif
/else
ブロックです。
条件の基本構造は次のとおりです。
{{ if PIPELINE }}
# Do something
{{ else if OTHER PIPELINE }}
# Do something else
{{ else }}
# Default case
{{ end }}
ここで、値ではなく*パイプライン*について説明していることに注意してください。 この理由は、制御構造は値を評価するだけでなく、パイプライン全体を実行できることを明確にするためです。
パイプラインは、値が以下の場合、*false*と評価されます。
- ブール値のfalse
- 数値のゼロ
- 空の文字列
nil
(空またはnull)- 空のコレクション(
map
、slice
、tuple
、dict
、array
)
その他すべての条件では、条件はtrueです。
ConfigMapに簡単な条件を追加してみましょう。飲み物がコーヒーに設定されている場合に、別の設定を追加します。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "coffee" }}mug: "true"{{ end }}
前回の例ではdrink: coffee
をコメントアウトしたので、出力にはmug: "true"
フラグは含まれません。 ただし、その行をvalues.yaml
ファイルに戻すと、出力は次のようになります。
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: eyewitness-elk-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: "true"
空白の制御
条件付きを検討している間に、テンプレートで空白がどのように制御されるかを見てみましょう。 前の例を取り上げて、少し読みやすくフォーマットしてみましょう。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "coffee" }}
mug: "true"
{{ end }}
最初は良さそうです。 しかし、テンプレートエンジンで実行すると、残念ながら次のような結果になります。
$ helm install --dry-run --debug ./mychart
SERVER: "localhost:44134"
CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart
Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key
何が起こったのでしょうか? 上記の空白のために、正しくないYAMLが生成されました。
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: eyewitness-elk-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: "true"
mug
のインデントが間違っています。 その1行のインデントを外して、再実行してみましょう。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{ if eq .Values.favorite.drink "coffee" }}
mug: "true"
{{ end }}
送信すると、有効なYAMLが得られますが、まだ少し奇妙に見えます。
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: telling-chimp-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: "true"
YAMLに空行がいくつかあることに注意してください。 なぜでしょうか? テンプレートエンジンが実行されると、{{
と}}
の間の内容は*削除*されますが、残りの空白はそのまま残ります。
YAMLは空白に意味を割り当てるため、空白の管理は非常に重要になります。 幸いなことに、Helmテンプレートには、役立つツールがいくつかあります。
まず、テンプレート宣言の中括弧構文は、特殊文字を使用して変更することで、テンプレートエンジンに空白を削除するように指示できます。 {{-
(ダッシュとスペースが追加されています)は、左側の空白を削除する必要があることを示し、-}}
は右側の空白を使用する必要があることを意味します。 *注意してください! 改行も空白です!*
-
とディレクティブの残りの部分の間にスペースがあることを確認してください。{{- 3 }}
は「左側の空白をトリミングして3を出力する」ことを意味し、{{-3 }}
は「-3を出力する」ことを意味します。
この構文を使用すると、テンプレートを変更してこれらの改行を削除できます。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}
{{- if eq .Values.favorite.drink "coffee" }}
mug: "true"
{{- end }}
この点を明確にするために、上記を調整し、このルールに従って削除される各空白を*
に置き換えてみましょう。 行末の*
は、削除される改行文字を示します。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
drink: {{ .Values.favorite.drink | default "tea" | quote }}
food: {{ .Values.favorite.food | upper | quote }}*
**{{- if eq .Values.favorite.drink "coffee" }}
mug: "true"*
**{{- end }}
これを念頭に置いて、テンプレートをHelmで実行して結果を確認できます。
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: clunky-cat-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
mug: "true"
削除修飾子には注意してください。 次のようなことを誤って行うのは簡単です。
food: {{ .Values.favorite.food | upper | quote }}
{{- if eq .Values.favorite.drink "coffee" -}}
mug: "true"
{{- end -}}
これは、両側の改行が使用されるため、food: "PIZZA"mug: "true"
が生成されます。
テンプレートでの空白制御の詳細については、公式のGoテンプレートドキュメントを参照してください。
最後に、テンプレートディレクティブの間隔をマスターしようとする代わりに、テンプレートシステムにインデント方法を指示する方が簡単な場合があります。 そのため、indent
関数({{ indent 2 "mug:true" }}
)を使用すると便利な場合があります。
with
を使用したスコープの変更
次に説明する制御構造は、with
アクションです。 これは変数のスコープを制御します。 .
は*現在のスコープ*への参照であることを思い出してください。 したがって、.Values
はテンプレートに現在のスコープでValues
オブジェクトを見つけるように指示します。
with
の構文は、単純なif
ステートメントに似ています。
{{ with PIPELINE }}
# restricted scope
{{ end }}
スコープは変更できます。 with
を使用すると、現在のスコープ(.
)を特定のオブジェクトに設定できます。 たとえば、私たちは.Values.favorite
を使用してきました。 ConfigMapを書き直して、.
スコープを.Values.favorite
を指すように変更してみましょう。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
with
の後にあるブロックは、PIPELINE
の値が空でない場合にのみ実行されるため、前の演習のif
条件は削除されたことに注意してください.
これで、.drink
と.food
を修飾せずに参照できるようになったことに注意してください。 これは、with
ステートメントが.
を.Values.favorite
を指すように設定するためです。 {{ end }}
の後、.
は前のスコープにリセットされます。
ただし、注意が必要です。 制限されたスコープ内では、.
を使用して親スコープから他のオブジェクトにアクセスすることはできません。 たとえば、これは失敗します。
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ .Release.Name }}
{{- end }}
Release.Name
は.
の制限されたスコープ内にないため、エラーが発生します。 ただし、最後の2行を入れ替えると、{{ end }}
の後にスコープがリセットされるため、すべてが期待どおりに機能します。
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
release: {{ .Release.Name }}
または、親スコープからオブジェクトRelease.Name
にアクセスするために$
を使用できます。 $
は、テンプレートの実行が開始されるとルートスコープにマップされ、テンプレートの実行中は変更されません。 次のようにしても機能します。
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
release: {{ $.Release.Name }}
{{- end }}
range
を確認した後、上記のスコープの問題に対する1つの解決策を提供するテンプレート変数を見ていきます。
range
アクションを使用したループ
多くのプログラミング言語は、for
ループ、foreach
ループ、または同様の機能メカニズムを使用してループをサポートしています。 Helmのテンプレート言語では、コレクションを反復処理するには、range
演算子を使用します。
まず、values.yaml
ファイルにピザのトッピングのリストを追加してみましょう。
favorite:
drink: coffee
food: pizza
pizzaToppings:
- mushrooms
- cheese
- peppers
- onions
これで、pizzaToppings
のリスト(テンプレートではslice
と呼ばれます)ができました。 このリストをConfigMapに出力するようにテンプレートを変更できます。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
{{- end }}
toppings: |-
{{- range .Values.pizzaToppings }}
- {{ . | title | quote }}
{{- end }}
親スコープからリストValues.pizzaToppings
にアクセスするために$
を使用できます。 $
は、テンプレートの実行が開始されるとルートスコープにマップされ、テンプレートの実行中は変更されません。 次のようにしても機能します.
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-configmap
data:
myvalue: "Hello World"
{{- with .Values.favorite }}
drink: {{ .drink | default "tea" | quote }}
food: {{ .food | upper | quote }}
toppings: |-
{{- range $.Values.pizzaToppings }}
- {{ . | title | quote }}
{{- end }}
{{- end }}
toppings:
リストを詳しく見てみましょう。 range
関数は、pizzaToppings
リストを「範囲指定」(反復処理)します。 しかし、ここで興味深いことが起こります。 with
が.
のスコープを設定するのと同じように、range
演算子も設定します。 ループを繰り返すたびに、.
は現在のピザのトッピングに設定されます。 つまり、最初は.
はmushrooms
に設定されます。 2回目の反復では、cheese
に設定されます。 以降も同様です。
.
の値をパイプラインに直接送信できるため、{{ . | title | quote }}
を実行すると、.
がtitle
(タイトルケース関数)に送信され、次にquote
に送信されます。 このテンプレートを実行すると、出力は次のようになります。
# Source: mychart/templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: edgy-dragonfly-configmap
data:
myvalue: "Hello World"
drink: "coffee"
food: "PIZZA"
toppings: |-
- "Mushrooms"
- "Cheese"
- "Peppers"
- "Onions"
この例では、トリッキーなことをしました。 toppings: |-
行は、複数行の文字列を宣言しています。 したがって、トッピングのリストは実際にはYAMLリストではありません。 大きな文字列です。 なぜこのようなことをするのでしょうか? ConfigMapsのdata
は、キーと値の両方が単純な文字列であるキー/値のペアで構成されているためです。 これについての詳細は、Kubernetes ConfigMapドキュメントを参照してください。 ただし、私たちにとっては、この詳細はそれほど重要ではありません。
YAMLの
|-
マーカーは複数行の文字列を受け取ります。これは、ここに示すように、マニフェスト内に大きなデータブロックを埋め込むための便利な手法です。
テンプレート内でリストをすばやく作成し、そのリストを反復処理できることが役立つ場合があります。Helmテンプレートには、これを簡単にするための関数tuple
があります。コンピュータサイエンスでは、タプルは固定サイズのリストのようなコレクションですが、任意のデータ型を持ちます。これは、tuple
の使用方法を大まかに表しています。
sizes: |-
{{- range tuple "small" "medium" "large" }}
- {{ . }}
{{- end }}
上記は以下を生成します
sizes: |-
- small
- medium
- large
リストとタプルに加えて、range
を使用して、キーと値を持つコレクション(map
やdict
など)を反復処理できます。テンプレート変数を導入する次のセクションで、その方法を説明します。