関数@チャート¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. 変数¶
予約された変数¶
デプロイツール内 (例:ArgoCD、Flux) でHelmを使用する場合、そのツールの実行環境に応じたバージョン値になる。
変数名 | デフォルト値 | 値 |
---|---|---|
.Release.Name |
リリース名 | |
.Release.Time |
リリースした時間 | |
.Release.Namespace |
リリースされる名前空間 | |
.Release.Service |
v3 の場合Helm 、v2 |
リリースに使用したツール名 |
.Release.Revision |
リリースのリビジョン番号 | |
.Release.IsUpgrade |
upgradeかrollback操作の場合、trueがセットされる | |
.Release.IsInstall |
install操作の場合、trueがセットされる | |
.Values |
valuesファイルもしくはユーザーから-fで指定されたファイルからテンプレートに渡される値。変数名は任意で定義。「Values.変数キー名」で変数の値を取得可能 | |
.Chart.ApiVersion |
Chart.yamlに記載されるチャートAPIのバージョン | |
.Chart.Name |
Chart.yamlに記載されるチャートの名前 | |
.Chart.Version |
Chart.yamlに記載されるチャート自体のバージョン | |
.Chart.KubeVersion |
Chart.yamlに記載される互換性のあるKubernetesバージョン | |
.Chart.Description |
Chart.yamlに記載されるチャートの概要一文 | |
.Chart.Home |
Chart.yamlに記載されるサイトのURL | |
.Chart.Sources |
Chart.yamlに記載されるソースコードのURL | |
.Chart.Maintainers |
Chart.yamlに記載されるチャートのメンテナーの名前とEmail(配列) | |
.Chart.engine |
Chart.yamlに記載されるテンプレートエンジン | |
.Chart.Icon |
Chart.yamlに記載されるアイコンのURL | |
.Chart.AppVersion |
Chart.yamlに記載されるコンテナアプリのバージョン | |
.Chart.Deprecated |
Chart.yamlに記載されるチャートの推奨/非推奨(boolean値) | |
.Capabilities.APIVersions |
Kubernetesリソースのバージョン | |
.Capabilities.APIVersions.Has |
そのkube-apiserverのバージョンで、そのAPIバージョンを使用可能かどうか。例えば、EndpointSliceは特定のバージョン以降でしか使用できない。 - https://github.com/prometheus-community/helm-charts/blob/0e2aa2e9c47e3eb5fadbb0186808bc5996001afe/charts/kube-prometheus-stack/templates/prometheus-operator/clusterrole.yaml#L82-L91 |
|
.Capabilities.KubeVersion |
コンテキストのKubernetesバージョン | |
.Template.Name |
カレントパスの相対ファイルパス | |
.Template.BasePath |
チャートのtemplatesディレクトリの相対パス |
ローカルスコープの変数¶
同じファイル内で使用できる変数を定義する。
{{- $domain := "https://{{ .Values.serviceName }}.argocd.com" }}
条件内スコープの変数¶
条件分岐で定義した変数は、{{- if }}
から{{- end }}
までしか使用できない。
{{- if .Values.isProduction }}
{{- $prefix := "prd" }}
... # 変数を使用する。
{{- else }}
{{- $prefix := "nonprd" }}
... # 変数を使用する。
{{- end }}
条件数が2`個しかない場合であれば、三項演算子の結果を変数に格納できる。
そのため、{{- if }}
から{{- end }}
の外側でも変数を使用できる。
# 実行環境はdevかprdしかないものとする。
# .values.environmentが "prd" の場合はprintf関数でサブドメインを作成し、それではない場合は空文字とする
{{- $subDomain := ternary (printf "%s." .values.environment ) "" .values.environment "prd" }}
url: https://{{ $subDomain }}{{.Values.serviceName }}.com
グローバルスコープの変数¶
テンプレートの関数 (例:include
、template
) 、_helpers.tpl
ファイルで定義する。
02. Helmのコメントアウト¶
Helmのテンプレート内にコメントアウトを定義する。
*/}}
にはスペースを含めずに、一繋ぎで定義する。
YAMLのコメントアウト (例:#
) であると、テンプレートの出力時に、YAMLのコメントアウトとしてそのまま出力されてしまうため、注意する。
Helmのコメントの前に不要な改行が挿入されないように、{{-
とする方が良い。
{{- /* コメント */}}
もしコメントの後にも改行が挿入されてしまう場合は、-}}
も付ける。
{{- /* コメント */-}}
*/}}
にはスペースを含めずに、一繋ぎで定義する。
03. テンプレート作成の関数¶
テンプレート作成の関数とは¶
template
ディレクトリ配下のテンプレートを出力する。
include¶
▼ includeとは¶
define
関数で定義したテンプレートを加工して出力する。
加工内容はパラメーターで設定できる。
template¶
▼ templateとは¶
define
関数で定義したテンプレートをそのまま出力する。
template
関数では出力内容を変数に格納できないため、これが可能なinclude
関数が推奨である。
04. values
ファイルの関数¶
Values¶
▼ Valuesとは¶
values
ファイルの特定のキー値を出力する。
特定の条件下で、values
ファイルを2階層以上に設定できなくなる現象の理由がわかっていない...。
# valuesファイル
global:
env: prd
appName: foo
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.global.env }}-{{ .Values.global.appName }}-pod
labels:
app.kubernetes.io/name: {{ .Values.global.appName }}
▼ metadataキーで使用する場合の注意点¶
マニフェストの`.metadata.
キーの値には文字列しか設定できない。
values
ファイルから出力した値が数字の場合、Helmは勝手にint型に変換しようとする。
そのため、metadataキーの値にint型を出力しようとしてエラーになってしまう。
int型にならないように、values
ファイルの出力先をダブルクオーテーションで囲うと良い。
# valuesファイル
metadata:
labels:
# マニフェストで、int型で出力しようとする。
id: "1"
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo
labels:
# int型にならないように、ダブルクオーテーションで囲う。
id: "{{ .Values.metadata.labels.id }}"
default¶
▼ defaultとは¶
出力された値が空文字 (""
) やfalse
の場合に、それを上書きしてデフォルト値として出力する。
キー自体は存在しなければならず、省略することはできないことに注意する。
{{.Values.foo | default "foo"}}
▼ キーが存在しなくてもデフォルト値を表現¶
isFoo
キーが存在し、またtrue
だった場合にマニフェストを出力する。
これにより、キーが存在しなくともfalse
が設定されているように振る舞える。
foo:
isFoo: "true"
params: FOO
bar:
params: BAR
{{- if hasKey .Values.foo "isFoo" }}
{{- if eq .Values.foo.isFoo true }}
...
{{- end }}
{{- else }}
...
{{- end }}
toYaml¶
▼ toYamlとは¶
出力されたデータをそのままの形で出力する。
values
ファイルにmap型やlist型をそのまま出力する場合に使用する。
▼ map型の場合¶
map型を出力する。
# valuesファイル
parameters:
foo: FOO
bar: BAR
apiVersion: v1
kind: Secret
metadata:
name: foo-secret
data: {{- toYaml .Values.parameters | nindent 2}}
▼ list型の場合¶
list型を出力する。
# valuesファイル
containers:
- name: foo
image: foo:latest
apiVersion: v1
kind: Pod
metadata:
name: foo-pod
spec:
containers: {{- toYaml .Values.containers | nindent 4}}
05. キーパスの関数¶
キーパスの関数とは¶
テンプレートやvalues
ファイルを出力する時に、特定のキーパスにリクエストを送信する。
.
(ドット)¶
▼ ドットとは¶
テンプレートの内容をルートから出力する。
{* tplファイル *}
{{- define "foo-template" }}
- foo: FOO
bar: BAR
{{- end }}
baz:
{{- include "foo-template" . }}
# 結果
baz:
- foo: FOO
bar: BAR
$
(ドル)¶
▼ ドルとは¶
出力時に、yaml
ファイルのルートを明示的に出力する。
アクションの中でアクションで、yaml
ファイルのルートにリクエストしたい場合に役立つ。
*実装例*
range
関数を使用すると、yaml
ファイルへのアクセスのルートが変わってしまう。
ルートを明示することにより、range
関数内でもyaml
ファイルの正しいルートにリクエストを送信できるようなる。
{{- range $.Values.foo.namespaces }}
apiVersion: apps/v1
kind: Secret
metadata:
name: {{ $.Values.global.env }}-foo-secret
namespace: {{ . }}
...
{{- end }}
06. ループの関数¶
range¶
▼ rangeとは¶
同じ階層にある他のyaml
ファイルのキーとその値を格納し、foreach
関数のように出力する。
▼ マップ型を扱う場合¶
マップ型を入力値として使用できる。
*実装例*
もし、以下のような平文ファイルがあるとする。
# plane.yamlファイル
foo: FOO
bar: bar
これをbase64
方式で変換し、values
ファイルのconfig
キー配下に定義したとする。
# valuesファイル
config: eHh4OiB5eXkKenp6OiBxcXEK
fromYaml
関数を使用して、string型をmap型に変換する。
その後、range
関数でキーと値を取得し、Secretのデータとして割り当てる。
{{- $decoded := .Values.config | b64dec | fromYaml }}
apiVersion: v1
kind: Secret
metadata:
name: foo-secret
type: Opaque
data:
{{- range $key, $value := ($decoded) }}
{{ $key }}: {{ $value }}
{{- end }}
*実装例*
マップ型の一番上層のキー名を反復的に取得する場合に役立つ。
config:
foo:
foo-sub: FOO-SUB
bar:
bar-sub: BAR-SUB
baz:
baz-sub: BAZ-SUB
{{- range $key, $value := .Values.config }}
{{- if or (eq $key "foo") (eq $key "baz") }}
apiVersion: v1
kind: ConfigMap
metadata:
# foo-map、baz-map、を作成できる。
# bar-mapは作成されない。
name: {{ $key }}-map
data:
...
{{- end }}
{{- end }}
▼ 配列型を扱う場合¶
配列型を入力値として使用できる。
# valuesファイル
ipAddresses:
- 192.168.0.1/32
- 192.168.0.2/32
- 192.168.0.3/32
apiVersion: v1
kind: ConfigMap
metadata:
name: blocked-ip-addresses-config-map
data:
# 『.』を指定し、反復的に出力する。
ip-addresses: |
{{- range .Values.ipAddresses }}
- {{ . }}
{{- end }}
with¶
YAMLの現在のパスを変更する。
foo:
foo1: FOO1
foo2: FOO2
apiVersion: v1
kind: ConfigMap
metadata:
name: foo-config-map
data:
# 現在のパスをfooに変更する。
{{- with .Values.foo }}
foo1: {{ .foo1 }}
foo2: {{ .foo2 }}
{{- end }}
required¶
▼ requiredとは¶
記入中...
07. データ型変換の関数¶
fromYaml¶
▼ fromYamlとは¶
string型をmap型に変換する。
*実装例*
もし、以下のような平文ファイルあるとする。
# plane.yamlファイル
foo: FOO
bar: bar
これをbase64
方式で変換し、values
ファイルのconfig
キー配下に定義したとする。
# valuesファイル
config: eHh4OiB5eXkKenp6OiBxcXEK
fromYaml
関数を使用して、string型をmap型に変換する。
{{- $decoded := .Values.config | b64dec | fromYaml }}
apiVersion: v1
kind: Secret
metadata:
name: foo-secret
type: Opaque
data:
{{- range $key, $value := ($decoded) }}
{{ $key }}: {{ $value }}
{{- end }}
splitList¶
▼ splitListとは¶
string型を指定した文字で分割し、list型に変換する
url: https://github.com/hiroki-hasegawa/foo-repository.git
# printf関数を使用して、一度strig型に変換している。
{{- printf "%s" .Values.url | splitList "/"}}
# [https: github.com hiroki-hasegawa foo-repository.git]
08. string型の関数¶
contains¶
指定した文字列が含まれているかを検証する。
{{- if contains .Values.env "prd"}}
... # prd という文字が含まれている場合
{{- else}}
... # prd という文字が含まれていない場合
{{- end}}
printf¶
▼ printfとは¶
様々なデータ型をstring型で出力する。
▼ エスケープ¶
Helmのテンプレート内に、アクションや変数以外の理由で{}
を出力する場合 (例:Alertmanagerのアラートの変数出力の定義) 、これらとして認識されないようにエスケープする必要がある。
また、エスケープする場合は必ず改行 (|
、|-
、|+
) で出力する必要がある。エスケープのためにprintf
関数を使用することもできる。
一方で、HelmではGoのテンプレートを使用していため、これと同じエスケープの方法 (例:{{`<記号を含む文字列全体>`}}
、{{"<記号>"}}
) を使用できる。
エスケープしたい文字列にバッククオートが含まれる場合、『{{`<記号を含む文字列>`}}
』を使用できず、他のエスケープ方法 ({{"<記号>"}}
、printf
関数) が必要になる。
# Helmのテンプレート
# Alertmanagerの通知内容の定義は以下を参考にした。
# https://www.infinityworks.com/insights/slack-prometheus-alertmanager/
---
receivers:
- name: slack_webhook
slack_configs:
- channel: prd
send_resolved: "true"
api_url: https://hooks.slack.com/services/*****
# 波括弧 ({}) をエスケープするために、『{{``}}』とprintfを使用している。
# エスケープする場合は、必ず改行で出力する必要がある。
text: |
{{`{{ range .Alerts }}`}}
{{`*Summary:* {{ .Annotations.summary }}`}}
{{ printf "*Severity:* `{{ .Labels.severity }}`" }}
{{`*Description:* {{ .Annotations.description }}`}}
*Details:*
{{ printf "{{ range .Labels.SortedPairs }} • *{{ .Name }}:* `{{ .Value }}`" }}
{{`{{ end }}`}}
{{`{{ end }}`}}
trimSuffix¶
▼ trimSuffixとは¶
string型から指定した文字を削除し、再取得する。
url: https://github.com/hiroki-hasegawa/foo-repository.git
# printf関数を使用して、一度strig型に変換している。
{{- $list := printf "%s" .Values.url | splitList "/" }}
# [https: github.com hiroki-hasegawa foo-repository.git]
# リポジトリ名のみを取得する。
{{- $repositoryName := last $list | trimSuffix ".git" }}
# foo-repository
08-02. list型の関数¶
last¶
▼ lastとは¶
list型の最後を取得する。
lists:
- foo
- bar
- baz # これのみを取得する
{{.Values.lists | last}}
# baz
09. セキュリティに関する機能¶
b64enc¶
▼ b64encとは¶
base64
方式でエンコードする。
Secretの.data
キーでは、他のKubernetesリソースへの出力時に自動的にbase64
方式でデコードするようになっており、相性が良い。
*実装例*
# valuesファイル
username: hiroki-it
password: pass
apiVersion: v1
kind: Secret
metadata:
name: foo-secret
data:
# base64方式でエンコードする。
username: {{.Values.username | b64enc}}
password: {{.Values.password | b64enc}}
*実装例*
リポジトリの認証情報を管理するSecretを繰り返し作成する。
{{- range .Values.github.repositories }}
{{- /*
URLからリポジトリ名を抽出する
Kubernetesのリソース名では一部の文字や記号を使用できないため、これに対処する
(例) "https://github.com/argoproj/argo-cd.git" から "argo-cd" のみを取得する
*/}}
{{- $repositoryName := printf "%s" . | splitList "/" | last | trimSuffix ".git" }}
{{- $name := regexReplaceAllLiteral "_" $repositoryName "-" }}
{{- /*
URLのbase64方式エンコード値を取得する
Kubernetesのリソース名では一部の文字や記号を使用できないため、これに対処する
(例) "https://github.com/argoproj/argo-cd.git" から "ahr0chm6ly9naxrodwiuy29tl2fyz29wcm9ql2fyz28ty2quz2l0" を取得する
*/}}
{{- $lowerbase64EncodedUrl := . | b64enc | lower }}
{{- $id := regexReplaceAllLiteral "[^a-z0-9]" $lowerbase64EncodedUrl "" }}
{{- /*
Secretの名前が必ず一意になるように、リポジトリ名とURLエンコード値で命名する
(例) "https://github.com/argoproj/argo-cd.git" のSecretの名前は "argo-cd-ahr0chm6ly9naxrodwiuy29tl2fyz29wcm9ql2fyz28ty2quz2l0" になる
*/}}
apiVersion: v1
kind: Secret
metadata:
name: foo-{{ $name }}-{{ $id }}
data:
# base64方式でエンコードする。
username: {{.Values.github.username | b64enc}}
password: {{.Values.github.password | b64enc}}
{{- end }}
▼ 変化しない一意な名前¶
セキュリティではなく、変化しない一意な名前のKubernetesリソース (特にConfigMap、Secret) を作成できるように、接尾辞にbase64方式のエンコード値を使用する。
# valuesファイル
repositoryUrls:
- https://github.com/argoproj/argo-cd
{{- range .Values.repositoryUrls | b64enc }}
apiVersion: v1
kind: ConfigMap
metadata:
# 名前が一意になるようにする。
name: foo-config-map-{{ . | b64enc }}
data:
url: {{ . }}
{{- end }}
genCA¶
▼ genCA¶
SSL証明書とペアになる秘密鍵を作成する。
SSL証明書は.Cert
、秘密鍵は.Key
でリクエストできる。
{{- $ca := genCA "foo-ca" 3650 }}
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
name: foo-webhook
webhooks:
clientConfig:
# SSL証明書を出力する
caBundle: {{ $ca.Cert | b64enc }}
...
sha256sum¶
▼ sha256sumとは¶
入力内容をハッシュ値に変換する。
SecretとConfigMapの設定値を変更した場合に、Podを配下にもつKubernetesリソース (例:Deployment、StatefulSet、DaemonSet) では、Podを再作成する必要がある。
これらのKubernetesリソースのPodTemplateの.metadata.annotations
キーにて、テンプレートの出力をsha256sum
に入力する。
これにより、SecretとConfigMapを変更した場合に、ハッシュ値が変更される。
そのため、PodTemplateが変更されたことになり、Podも再作成できるようになる。
*実装例*
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo-deployment
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: foo-pod
template:
metadata:
annotations:
checksum/secret: "{{ include (print $.Template.BasePath '/foo-secret.yaml') . | sha256sum }}"
checksum/configmap: "{{ include (print $.Template.BasePath '/foo-configmap.yaml') . | sha256sum }}"
spec:
containers:
- name: app
image: app:1.0.0
ports:
- containerPort: 8080
envFrom:
- secretRef:
name: foo-secret
- configMapRef:
name: foo-secret
10. インデントの関数¶
-
(ハイフン)¶
▼ {{-
¶
{{-
であると、テンプレートの出力時にこれより前のインデントを削除する。
*実装例*
{* tplファイル *}
{{- define "foo-template" }}
- foo: FOO
bar: BAR
{{- end }}
baz: {{- include "foo-template" .}} # 『{{-』の前にあるインデントは削除される。
# 結果
baz:
- foo: FOO
bar: BAR
▼ -}}
¶
-}}
であると改行コードを削除し、不要な改行が挿入されないようにする。
Helmの関数の中には処理結果に改行コードを挿入するものがあるため、これを削除したい場合に役立つ。
ただし基本的には、-}}
は使用しない方が良いらしい。
indent¶
▼ indentとは¶
改行せずに、そのままスペースを挿入した上で、内容を出力する。
nindent
関数とは、改行しない点で異なる。
*実装例*
{* tplファイル *}
{{- define "foo-template" }}
- foo: FOO
bar: BAR
{{- end }}
# 2つ分のスペースを挿入した上で、出力する。
baz:
{{- include "foo-template" . | indent 2 }}
# 結果
baz:
- foo: FOO
bar: BAR
nindent¶
▼ nindentとは¶
改行しつつ、スペースを挿入した上で、内容を出力する。
indent
関数とは、改行する点で異なる。
*実装例*
{* tplファイル *}
{{- define "foo-template" }}
- foo: FOO
bar: BAR
{{- end }}
# 改行しつつ、2つ分のスペースを挿入した上で、出力する。
baz:
{{- include "foo-template" . | nindent 2 }}
# 結果
baz:
# ここで改行が入る
- foo: FOO
bar: BAR
11. 検証の関数¶
hasKey¶
▼ hasKeyとは¶
指定したキーが存在する場合、true
を返却する。
キーが存在する場合にのみ、そのキー配下の構造を使用するような場面で役立つ。
一方で、別途enabled
キーを用意するのもありである。
foo:
baz:
- FOO
- BAR
foo:
{{- if hasKey .Values.foo "baz" }}
baz:
{{- range .Values.foo.baz }}
- {{ . }}
{{- end }}
...
{{- end }}
▼ indexでも代用可¶
index
関数でhasKey
関数を代用できる。
指定した文字列が存在する場合、true
を返却する。
foo:
baz:
- FOO
- BAR
foo:
{{- if (index .Values.foo "baz") }}
baz:
{{- range .Values.foo.baz }}
- {{ . }}
{{- end }}
...
{{- end }}
12. 条件分岐の関数¶
単一条件¶
eq
演算子を使用する。
{{- if eq .Values.enableFoo true }}
...
{{- end }}
AND条件¶
and
演算子と()
記号を使用する。
{{- if and (eq .Values.enableFoo true) (eq .Values.enableBar true) }}
...
{{- end }}
OR条件¶
or
演算子と()
記号を使用する。
{{- if or (eq .Values.global.env "tes") (eq .Values.global.env "stg") }}
...
{{- end }}
NOT条件¶
ne
演算子 (not equalの略) を使用する。
{{- if ne .Values.global.env "tes" }}
...
{{- end }}
13. ファイル系¶
Files¶
ファイルから内容を取得する。
.Files.Glob
関数で複数のファイルをmap型で取得できる。
{{- range $filePath, $_ := .Files.Glob "dashboards/*.json" }}
{{- $dashboardName := regexReplaceAll "(^.*/)(.*)\\.json$" $path "${2}" }}
apiVersion: v1
kind: ConfigMap
metadata:
name: grafana-dashboard-{{ $dashboardName }}
namespace: prometheus
labels:
grafana_dashboard: "1"
data:
{{ $dashboardName }}.json: {{ $.Files.Get $filePath }}
---
{{- end }}
- - https://helm.sh/docs/chart_template_guide/function_list/#file-functions - https://helm.sh/docs/chart_template_guide/accessing_files/ - https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14 - https://stackoverflow.com/questions/64662568/how-can-i-use-a-json-file-in-my-configmap-yaml-helm - https://github.com/helm/helm/issues/4515#issuecomment-415303665
14. 例外処理系¶
fail¶
エラーメッセージを含む例外をスローし、意図的に処理を失敗させる。
他のメンバーに設計方針を強制したり、必須値を定義する場合に使用する。
{{- if not (contains .Values.foo $bar) }}
{{- fail "〇〇であると△△のため、barにはfooを含むようにしてください" }}
{{- else }}
...
{{- end }}