--- title: ytt(YAML Templating Tool)入門 - Templating編 tags: ["YAML", "ytt", "k14s", "Carvle"] categories: ["Dev", "Carvel", "ytt"] date: 2020-08-19T06:44:46Z updated: 2020-08-27T14:25:46Z --- [ytt](https://get-ytt.io)はスタンドアローンで使えるYAMLのテンプレートツールです。同じ領域のツールとしては * [Jsonnet](https://jsonnet.org) * [Dhall](https://dhall-lang.org) * [Cue](https://cuelang.org) がありますが、テンプレートツールとしてのyttの特徴としては * YAMLそのものを記述する(YAMLとしてvalid) * YAMLのコメントとしてPython-likeな[Starlark](https://github.com/google/starlark-go/blob/master/doc/spec.md)言語を記述することで動的な表現ができる 各ツールとの比較の詳細は[こちら](https://github.com/k14s/ytt/blob/develop/docs/ytt-vs-x.md)。 他のツールが専用の言語を使うのに比べ、yttはあくまでもYAML+コメントなので心理的な導入のハードルは低いかもしれません。 もちろんytt用に文法は覚える必要はありますが、言語部分もPythonを使ったことがあれば覚えやすいかもしれません。 ただし、yttはただのテンプレートツールとは異なり、overlay機能を持っています。これはYAMLの一部を書き換えたり、追加したり、削除したりできる強力な機能で、 Kubernetesの[Kustomize](https://kubernetes-sigs.github.io/kustomize/api-reference/glossary/#overlay)やBOSHの[Operation files](https://bosh.io/docs/cli-ops-files)と同じような機能です。
つまり、Templating + Overlayが大きなyttの機能です。 本記事ではTemplating機能のみフォーカスします。Overlay機能については[次の記事](/entries/545)で説明します。 yttの仕様は[こちら](https://github.com/k14s/ytt/blob/develop/docs/lang.md)です。 **目次** ### インストール [こちら](https://github.com/k14s/ytt/releases)からバイナリをダウンロードするか、 ``` curl -sL https://k14s.io/install.sh | bash ``` あるいは ``` brew tap k14s/tap brew install ytt ``` でインストールできます。 ### 基本的な書き方 yttのYAMLは次の形式のコメントを使用します。それ以外のコメント(普通のYAMLのコメント)を書くとエラーになります。 エラーを許容する場合は`--ignore-unknown-comments`オプションをつける必要があります。 ```yaml #! YAMLのコメント #@ Starlark言語の値またはコード ``` YAMLの値の部分にStarlarkの値を使って次の`config.yml`を作成します。 ```yaml null_value: #@ None boolean_true: #@ True boolean_false: #@ False string_value: #@ "Hello World!" string_format: #@ "Hello {}!".format("ytt") list_value: #@ ["a", "b", "c"] list_range: #@ list(range(0, 5)) map_value: #@ {"a": 100, "b": 200, "c": "Hello"} ``` このファイルを`ytt`コマンドに入力すると次のような出力を得られます。 ``` $ ytt -f config.yml null_value: null boolean_true: true boolean_false: false string_value: Hello World! string_format: Hello ytt! list_value: - a - b - c list_range: - 0 - 1 - 2 - 3 - 4 map_value: a: 100 b: 200 c: Hello ``` Python同様にリスト内包表記も利用できます。 ```yaml servers: #@ ["server-{}".format(x) for x in range(5)] ``` 次のような出力結果になります。 ``` $ ytt -f config.yml servers: - server-0 - server-1 - server-2 - server-3 - server-4 ``` ### 変数 変数の定義と参照ができます。 ```yaml #@ message = "Hello!" #@ coins = { #@ "penny": 1, #@ "nickel": 5, #@ "dime": 10, #@ "quarter": 25, #@ } message: #@ message conis: #@ coins dime: #@ coins["dime"] conin_keys: #@ coins.keys() conin_values: #@ coins.values() ``` 次のような出力結果になります。 ``` $ ytt -f config.yml message: Hello! conis: penny: 1 nickel: 5 dime: 10 quarter: 25 dime: 10 conin_keys: - penny - nickel - dime - quarter conin_values: - 1 - 5 - 10 - 25 ``` ### 関数 関数の定義、呼び出しができます。 ```yaml #@ def twice(x): #@ return x * 2 #@ end foo: #@ twice(7) list: #@ [twice(x) for x in [1, 2, 3]] ``` Python/Starlarkとは異なり、関数の定義は`end`で閉じる必要があります。 次のような出力結果になります。 ``` $ ytt -f config.yml foo: 14 list: - 2 - 4 - 6 ``` YAML Fragmentを関数として定義することもできます。 ```yaml #@ def labels(): organization: demo space: develop #@ end labels: #@ labels() ``` 次のような出力結果になります。 ``` $ ytt -f config.yml labels: organization: demo space: develop ``` ### If文 If文が利用できます。これも`end`が必要です。 ```yaml #@ enabled = True #@ if enabled: foo: enabled #@ else: foo: disabled #@ end ``` 次のような出力結果になります。 ``` $ ytt -f config.yml foo: enabled ``` if/elseを一行で表現することもできます。 ```yaml foo: #@ "enabled" if enabled else "disabled" ``` elseが不要でかつ、1ブロックだけを制御したい場合は`if/end`で省略できます。 ```yaml #@ enabled = True #@ if/end enabled: foo: enabled ``` ### For文 For文が利用できます。これも`end`が必要です。 ```yaml #@ for i in range(5): - #@ i #@ end ``` 次のような出力結果になります。 ``` $ ytt -f config.yml - 0 - 1 - 2 - 3 - 4 ``` 次のような書き方もできます。 ``` #@ foo = ["a", 1], ["b", 2], ["c", 3] #@ for a, i in foo: - key: #@ a value: #@ i #@ end ``` 次のような出力結果になります。 ``` $ ytt -f config.yml - key: a value: 1 - key: b value: 2 - key: c value: 3 ``` ### モジュール作成 関数の定義を別ファイルに外部化して、モジュールとして読み込むことができます。 次の`demo.lib.yml`を用意します。 ```yaml #@ def labels(): organization: demo space: develop #@ end ``` `load("モジュール名", "関数名", "関数名", ...)`で関数を読み込めます。 ```yaml #@ load("demo.lib.yml", "labels") labels: #@ labels() ``` 次のような出力結果になります。 ``` $ ytt -f config.yml -f demo.lib.yml labels: organization: demo space: develop ``` モジュールファイルは拡張子の前に`.lib`が必要です。これがないとマルチドキュメントなYAMLとして、出力結果に含まれてしまいます。 モジュールはStarlarkでも記述できます。 ```python # demo.star def square(x): return x * x end ``` ```yaml #@ load("demo.star", "square") value: #@ square(7) ``` 次のような出力結果になります。 ``` $ ytt -f config.yml -f demo.star value: 49 ``` ### 組み込みライブラリの利用 組み込み`ytt`ライブラリが用意されています。 https://github.com/k14s/ytt/blob/develop/docs/lang-ref-ytt.md `ytt`ライブラリの`base64`モジュールを使う例です。 ```yaml #@ load("@ytt:base64", "base64") #@ raw_value = "Hello World!" value: #@ base64.encode(raw_value) ``` 次のような出力結果になります。 ``` $ ytt -f config.yml value: SGVsbG8gV29ybGQh ``` > Note: yttでは次のように用語を使っています。 > > * モジュール ... YAMLや関数などを含む単一ファイル > * パッケージ ... モジュールを含む単一ディレクトリ > * ライブラリ ... パッケージの集合 > > https://github.com/k14s/ytt/blob/develop/docs/lang-ref-load.md#terminology ### カスタムライブラリの作成 `_ytt_lib`ディレクトリにカスタムライブラリを作成できます。 外部プロジェクトを`git submodule`で取得したり、[`vendir`](https://github.com/k14s/vendir)で取得した場合に配置する良いです。 簡単なサンプルとして[https://github.com/making/demo-lib](https://github.com/making/demo-lib)を取り込みましょう。 ``` mkdir -p _ytt_lib/github.com/making/demo-lib curl -sL https://github.com/making/demo-lib/archive/master.tar.gz | tar -xzvf - -C _ytt_lib/github.com/making/demo-lib --strip-components=1 ``` 次のディレクトリ構造になります。 ``` $ tree . . |-- _ytt_lib | `-- github.com | `-- making | `-- demo-lib | `-- demo.star `-- config.yml ``` `config.yml`でこの`github.com/making/demo-lib`ライブラリの`demo.star`モジュールを使用します。 ```yaml #@ load("@github.com/making/demo-lib:demo.star", "square") value: #@ square(7) ``` 次のような出力結果が得られます。 ``` $ ytt -f . value: 49 ``` 詳細は * https://github.com/k14s/ytt/blob/develop/docs/lang-ref-load.md * https://github.com/k14s/ytt/blob/develop/docs/lang-ref-ytt-library.md ### Assert `ytt`ライブラリの`assert`モジュールで入力チェックができます。 ```yaml #@ load("@ytt:assert", "assert") #@ foo = 200 foo: #@ foo if foo > 150 else assert.fail("'foo' must be greater than 150.") ``` nullチェックは次のように記述できます。 ```yaml #@ load("@ytt:assert", "assert") #@ iaas = "vsphere" iaas: #@ iaas or assert.fail("'iaas' is required!") ``` これは次の例の短縮版です。 ```yaml #@ load("@ytt:assert", "assert") #@ iaas = "vsphere" iaas: #@ iaas if iaas else assert.fail("'iaas' is required!") ``` ### Dataの外部化 変更可能な設定項目を外部YAMLに切り出すことができます。 次の`values.yml`に設定項目を記述します。`#@data/values`アノテーションをつけてください。 ```yaml #@data/values --- vsphere: hostname: vcsa-01.example.com username: administrator@vsphere.local password: VMware1! ``` `ytt`ライブラリの`data`モジュールを使って読み込みます。 `#@data/values`アノテーションをつけたファイルを`ytt`コマンドの入力に含めると、`data.values.xxxxx`で参照できるようにんります。 ```yaml #@ load("@ytt:data", "data") iaas-configurations: - vcenter_host: #@ data.values.vsphere.hostname vcenter_username: #@ data.values.vsphere.username vcenter_password: #@ data.values.vsphere.password ``` 次のように結合されて出力されます。 ``` $ ytt -f config.yml -f values.yml iaas-configurations: - vcenter_host: vcsa-01.example.com vcenter_username: administrator@vsphere.local vcenter_password: VMware1! ``` 設定項目は`ytt`コマンドの`-v`オプションで上書きできます。 ``` $ ytt -f config.yml -f values.yml -v vsphere.password=password iaas-configurations: - vcenter_host: vcsa-01.example.com vcenter_username: administrator@vsphere.local vcenter_password: password ``` JSONを読み込む例も紹介します。Terraformなど別のツールの結果がJSONとして出力され、それをそのまま読み込みたいケースを想定します。 次の`values.json`があるとします。 ```json { "vsphere": { "hostname": "vcsa-01.example.com", "password": "VMware1!", "username": "administrator@vsphere.local" } } ``` JSONファイルを文字列として読み込み、`json`モジュールでdecodeします。 ```yaml #@ load("@ytt:data", "data") #@ load("@ytt:json", "json") #@ values = json.decode(data.read("values.json")) iaas-configurations: - vcenter_host: #@ values["vsphere"]["hostname"] vcenter_username: #@ values["vsphere"]["username"] vcenter_password: #@ values["vsphere"]["password"] ``` 次のような出力結果を得られます。 ``` $ ytt -f config.yml -f values.json iaas-configurations: - vcenter_host: vcsa-01.example.com vcenter_username: administrator@vsphere.local vcenter_password: VMware1! ``` 同様に`yaml`モジュールでデコードする例をみてみます。 次の[Concourse](https://concourse-ci.org)の`pipeline.yml`で、Taskの`config`以下のYAMLを別ファイルに外出ししたい場合。 ```yaml jobs: - name: hello-world plan: - task: say-hello config: platform: linux image_resource: type: docker-image source: repository: ubuntu tag: bionic run: path: bash args: - -c - | echo "Hello, world!" ``` 切り出したTaskファイルを`hello.lib.yml`というファイル名で保存します。ファイル名に`.lib`を含めるのは、読み込まれた際にマルチドキュメントなYAMLとして出力されないようにするためです。 ```yaml platform: linux image_resource: type: docker-image source: repository: ubuntu tag: bionic run: path: bash args: - -c - | echo "Hello, world!" ``` `pipeline.yml`で、この`hello.lib.yml`を`data`モジュールで文字列としてとして読み込み、`yaml`モジュールでdecodeし、`config`に設定します。 ```yaml #@ load("@ytt:data", "data") #@ load("@ytt:yaml", "yaml") jobs: - name: hello-world plan: - task: say-hello config: #@ yaml.decode(data.read("hello.lib.yml")) ``` 次のようなディレクトリ構造にします。 ``` $ tree . . ├── pipeline.yml └── tasks └── hello.lib.yml ``` 次のコマンドで一つのpipelineに結合されます。 ``` $ ytt -f pipeline.yml -f tasks jobs: - name: hello-world plan: - task: say-hello config: platform: linux image_resource: type: docker-image source: repository: ubuntu tag: bionic run: path: bash args: - -c - echo "Hello, world!" ``` ### Textテンプレート 最初に`"文字列".format(...)`で文字列内に変数を埋める例を紹介しましたが、複数行の文字列に変数を埋め込みたい時は `@yaml/text-templated-strings`アノテーションをつけると便利です。 次のようなファイルが、 ```yaml #@ customer_name = "John Doe" #@yaml/text-templated-strings message: | Dear (@= customer_name @), Thanks for reading this blog post. Best regards, @making ``` 次のように出力されます。 ``` $ ytt -f config.yml message: |- Dear John Doe, Thanks for reading this blog post. Best regards, @making ``` テンプレートの部分は別ファイルに切り出せます。`message_body.lib.txt`に次の内容を記述し、 ``` (@ def message_body(customer_name): -@) Dear (@= customer_name @), Thanks for reading this blog post. Best regards, @making (@- end @) ``` 次のように読み込めば、 ```yaml #@ load("message_body.lib.txt", "message_body") #@ customer_name = "John Doe" message: #@ message_body(customer_name) ``` 次のように出力されます。 ```yaml $ ytt -f config.yml -f message_body.lib.txt message: |- Dear John Doe, Thanks for reading this blog post. Best regards, @making ``` --- yttのTemplating機能を見てきました。[次の記事](/entries/545)はYAMLの柔軟な加工に便利なOverlay機能を見ます。