コンテンツにスキップ

Kubernetes マニフェストジェネレータ

2021-08-09

Kubernetes のマニフェスト定義は細かく色々書けるのは良いのだが、そのリソース定義に特徴的な部分が埋もれてしまう欠点がある。 プログラミング上では頻出する課題で、汎用的な部分をベースの記述と、ベースからの差分の記述に分けて合成するのが典型的な解法。 似たような定義のリソースを作る場合にも、共通部分をベースに抜き出して再利用することで、重複記述の手間を避けてミスも減らすことができる。

Kubernetes にはこのようなことをやるツールが色々ある。 この分野に対するデファクトな名前は無さげ? マニフェストジェネレータ、と呼称する。

Helm Chart

一応の事実上の標準。 k8s にデプロイするためのマニフェストは大体 Helm Chart 形式で配布されている。

Helm そのものはパッケージリポジトリとしての機能もあったりしたのだが、ここではマニフェストジェネレータの部分を見る。 実態は Golang Template である。 というか Helm Chart の書き方的なドキュメントすら無く、Go Template のマニュアルを読むことになる。

Go Template はよくある HTML ジェネレータみたいなテンプレート言語である。

自分で色々書いてみたのはもう数年前なので詳細は曖昧だが、とても苦労した記憶がある。

マニフェストの型

単に文字列を置き換えるテンプレートエンジンなので、k8s マニフェストはもちろん、YAML 構造のチェックはしてくれない。 生成されたマニフェストのエラーを見つけるのが大変。

インデント

単純に置換されるので、インデントを扱うのが大変。

1
2
3
4
    resources:
{{ .Values.resources | toYaml | indent 8 }}
    volumes:
    - ...

{{-, -}} で前後の空白と後ろの改行を消せるのでそれを使えるが、

1
2
3
4
    resources:
      {{- .Values.resources | toYaml }}
    volumes:
    - ...

if 文を付けたりすると、end で改行がズレないように気を付けないとならない。

1
2
3
4
5
    resources:
      {{- if .Values.resources }}
      {{ .Values.resources | toYaml }}{{- end }}
    volumes:
    - ...

| で埋め込み YAML/JSON を使ったりすると地獄である。

パラメータの型

パラメータは各種基本型が使える。 しかし ArgoCD などで Helm Chart を適用する際には int や bool は string で渡さなければならなかった。

ループなど

テンプレートエンジンなので構造化データの処理が弱い。

たとえば入力の array[dict] に対して filter-map してマニフェストの一部を生成したいケースなどでは、begin-end の対が分かりにくいプレースホルダが散りばめられることになる。 もちろんプレースホルダ置く時はインデントに注意しないとならない。

まとめ

インデント合わせなど非生産的なことに時間をとられるストレスが凄い。 テンプレートエンジンとしてもそもそも文字列処理などが弱い。 使いたくない。

配布ツールとしてはデファクトなので利用はする。


Kustomize

Kubernetes-sigs CLI スポンサードのツールで、kubectl から使える。

マニフェストYAML の部分ファイル(リソースファイル)群と、それらの結合方法を指示する kustomization.yaml ファイルから成る。 それぞれのリソースファイルは apiVersion, kind, spec などを持った kubernetes マニフェストファイルで、どんどん上書きしていくスタイル。 プレースホルダを持ったテンプレートにパラメータを適用するテンプレートエンジンスタイルとは異なる。

それぞれのリソースファイルの内容は分かりやすく、単純な生成には便利。 環境毎に適用ファイルを変えることができる。 しかしプログラマブルにデータ処理はできない。

まとめ

基本的に重複上等で書きまくれという運用文化のツール。 プログラマには受け入れ難い。


jsonnet

JSON の厳格なところ(リストの最後の要素の後カンマを打っちゃだめとか)を緩くした言語。 関数呼び出しができる。関数定義もできる。 Python の内包表記みたいなリスト/辞書操作機能を備えてる。

リスト操作が強い。これだけで運用文化のツールででできない処理がだいたい出来る。

便利機能があるが特徴的で、学習が必要。 :: で定義したキーは最終出力から外れるとか、キーを if 文で指定して null だったら除外されるとか。

パラメータも jsonnet or json で書いて import で取り込むスタイル。 Helm Template のパラメータ渡しの型の問題は無い。

ArgoCD も対応してる。

まとめ

機能的には最小限度を満たしている。

癖があるので学習が必要なのと、最終的なマニフェストは YAML になるので JSON との対応付けが少し手間取るのが問題か。


ksonnet / tanka

jsonnet に k8s マニフェスト型への対応を入れ、k8s デプロイ機能を加えたもの。 k8s マニフェストの作りから、プログラミングスタイルも強制される。 config の取り込みの方法とか、ベースオブジェクトへの差分適用の方法とか。

デプロイ機能はステート管理は無いものの、現状との差分を出力してくれる。

ksonnet はディスコンになったが、Grafana チームが fork して tanka を作った。 ArgoCD は ksonnet は対応してるけど tanka は未対応。

tanka は helm chart のデプロイもできる。

まとめ

k8s マニフェスト型に対応しているのは強い。 helm chart が使えるのも、標準の配布ファイルが使えて便利。

デプロイ時の差分表示も便利。 チームでの利用や、自動デプロイには少し機能が不足。

あとは分かりにくいという jsonnet の欠点はそのままある。

個人プロジェクトや一人運用担当で使うのは有りか。


Pulumi

元々は Terraform のようなクラウド用 IoC ツールであったが、k8s にも対応した。

プログラミング言語でマニフェストを生成する。 言語は Typescript, Go, C# など対応。 もちろん k8s マニフェストの型定義がある。コンパイルエラーで弾けるのはもちろん、IDE によるプログラミング支援も。

ステート管理にサーバーが必要なようだ。 チーム利用は料金かかる。無料枠あり。自分でサーバー立てられるかも。

GitOps もできるようだ。

まとめ

プログラマとしてはとても魅かれる。 Terraform も k8s 対応してるみたいだけど、あっちはプログラマブル機能弱いし比較対象外。

価格はちょっと気になる。 無料枠がどの程度か深く計算していないが、まだ利益出てないスタートアップには躊躇われる。

まだ使い始めで、複雑なケースでのベストプラクティスがどうなるかは未知。 おためしでちょっとしたシステムデプロイの IoC 書いてみた: https://github.com/dai1975/pulumi-k8s-scaffold Input/Output の扱いがちょっと難しい。 あと、複数のプロジェクトに分割した場合に、基盤の方を更新しても依存される側は自動的に更新されないなというところ。 モノシリックスタックで良いのではないか疑惑。