はじめに
Helmチャートの構成で出てくる_helpers.tplの使い所がいまいちわかっていなかったので、自分が理解する目的も含めて本記事で書いてみます。
helm create [チャート名]でHelmチャートのひな形を作ると以下の構成ができると思いますが、templatesディレクトリにできる_helpers.tplというファイルが今回記事の主題です。
.
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl # 一体どう使うの??
│ ├── deployment.yaml
│ ...
└── values.yaml
values.yamlの使い方の確認
_helpers.tplの前に、まずは「values.yamlがどんな風な使われ方をするのか」を考えてみましょう。
values.yamlは、Helmチャートで使用されるデフォルトのパラメータが記載されたものです。以下は簡単な例ですが、Deploymentリソースのパラメータが定義されています。
replicas: "3"
name: nginx
image: docker.io/nginx:1.25.1
templatesディレクトリにはdeployment.yamlがあり、次のようにvalues.yamlの値を参照しています。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: {{ .Values.name }}
name: {{ .Values.name }}-deployment
spec:
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app: {{ .Values.name }}
template:
metadata:
labels:
app: {{ .Values.name }}
spec:
containers:
- image: {{ .Values.image }}
name: {{ .Values.name }}
デフォルトの値でそのままDeploymentリソースをデプロイする場合は、helm installコマンドを次のように実行します。
helm install nginx .
デフォルト以外の値にしたい場合は、例えば--setオプションを使って変更可能です。
helm install nginx . --set replicas=2
こうして改めて見てみると、Helmチャートによるデプロイを「プログラムの実行」と見なせば、values.yamlはプログラムを実行する際のconfigファイルやコマンドライン引数に相当するものと思ってもよさそうです。
もう一つDeploymentリソースが加わる
ここでDeploymentにnginxだけではなくて、httpdも使う必要が出てきました。httpdのDeploymentを追加で作ってみたところ、「マニフェストの構造が全く同じで値だけが違う」という結果になってしまいました...
現在のディレクトリ構造は以下のような感じです。deployment-httpd.yamlとdeployment-nginx.yamlがだいたい同じような内容になっている状態で悩ましいのです。
.
├── Chart.yaml
├── charts
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl # どう使うの?
│ ├── deployment-httpd.yaml # ↓ほぼ同じ内容...
│ └── deployment-nginx.yaml # ↑ほぼ同じ内容...
└── values.yaml
プログラムを書いた経験のある方だと「全く同じ内容が出てきたら関数にすればいいんじゃない!?」と思われるかもしれません。Helmチャートでも関数みたいな書き方が出来ると今の冗長な書き方を回避できるのですが、そんな事ができるのでしょうか?
_helpers.tplで関数みたいに書いてみる
結論から言うと _helpers.tplで関数のような書き方をすることができ、上の課題を解決できます。
細かい説明は置いといて、先に出てきたtemplates/deployment.yamlを少し変えて、Deploymentリソースのテンプレートを_helpers.tplに書いてみましょう。
{{- define "deployment" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: {{ .name }}
name: {{ .name }}-deployment
spec:
replicas: {{ .replicas }}
selector:
matchLabels:
app: {{ .name }}
template:
metadata:
labels:
app: {{ .name }}
spec:
containers:
- image: {{ .image }}
name: {{ .name }}
{{- end -}}
templates/deployment.yamlとの違いは以下の2点です。
- 変数を参照する
{{ .Values.xxxx }}の記述を{{ .xxxx }}に変更する - 最初に
{{- define "deployment" -}}、最後に{{- end -}}をつける
若干ネタバレになりますが、関数に例えると上記の内容は今後以下のように使われていきます。
-
{{- define "deployment" -}}のdeploymentが関数の名前 - その中で使われている
{{ .xxxx }}が関数の引数を通して渡された変数 - 戻り値は
{{- define "deployment" -}}から{{- end -}}までの部分に変数を代入してレンダリングされたテキスト(具体的にはDeploymentのマニフェスト)
関数を呼ぶ部分を作る
続いて_helpers.tplにdefineしたdeploymentを呼ぶ部分を作ります。プログラムの関数だとdeployment(引数)のような書き方になると思いますが、Helmの場合は
{{ include "deployment" 引数 }}
のような書き方で実現できます。
{{ include ... }} は {{ template ... }}とも書けるようですが、ざっと調べた感じ基本的にはincludeを使っていてよさそうです。
この書き方ができれば、各DeploymentのYAMLファイルは次のようにたったの1行で表現できます。
{{ include "deployment" nginx用の引数 }}
{{ include "deployment" httpd用の引数 }}
関数の引数として使う変数を設定する
上記各YAMLファイルで「nginx用の引数」「httpd用の引数」と曖昧に書きましたが、具体的にどのように設定すればいいのでしょうか?
この「引数」に相当する部分は、value.yamlに定義した値を設定することができます。今回はnginx用とhttpd用とで値を設定したいので、value.yamlに次のように書いてみます。
nginx:
replicas: "1"
name: nginx
image: docker.io/nginx:1.25.1
httpd:
replicas: "3"
name: httpd
image: docker.io/httpd:2.4.57
このように書くと、includeの引数は次のように指定してvalues.yamlの値を取得できます。
{{ include "deployment" .Values.nginx }}
{{ include "deployment" .Values.httpd }}
少し解説
.Values.nginxと.Values.httpdは、それぞれ「values.yamlのnginxおよびhttpdの配下を引数として渡している」感じになります。nginxとhttpdの下にはreplicas、name、imageのKeyValueがありますが、これら3つがdeploymentの .replicas、.name、.imageに対応しています。
デプロイの確認
次のように問題なくデプロイできるのを確認できます。
helm install nginx-and-httpd .
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
httpd-deployment 3/3 3 3 54s
nginx-deployment 1/1 1 1 54s
$ kubectl get po
NAME READY STATUS RESTARTS AGE
httpd-deployment-77d86486fb-k4d5l 1/1 Running 0 73s
httpd-deployment-77d86486fb-l2wm7 1/1 Running 0 73s
httpd-deployment-77d86486fb-r2nf4 1/1 Running 0 73s
nginx-deployment-5c5c5dfff9-w25hz 1/1 Running 0 73s
おわりに
実際の例をもとに_helpers.tplを使い、defineがプログラムの関数のような使い方ができることを確認できました。defineは今回ご紹介した内容以外でも便利な使い方ができるはずなので、私自身も今後勉強していきたいと思います。