YAMLとは?
概要
YAMLはJSONやXMLと同様にデータを構造化して保存するためのフォーマットです。一方、YAMLは人間が読みやすく書きやすいことを重視して設計されています。そのため見た目で階層構造が把握できるようインデントやスペースを使ってデータの階層構造を表現します。
そしてYAMLを学ぶ大きな理由の1つは、多くのIaC(Infra as Code)サービスの設定ファイル形式として利用されることが多いためです。例えばDockerComposeやAnsible、Kubernetesといったツールが挙げられます。
YAMLを理解する方法
前述のようにYAMLとJSONはデータを構造化して表現することができ、お互い変換が可能です。特にYAMLの文法に慣れないうちはJSONと比較するとわかりやすいので、オンラインツールであるTransform YAML into JSON(YAMLからJSONに変換)、Convert JSON to YAML online(JSONからYAMLに変換)などを利用しながら表記を確認してみることをおススメします。
押さえておくべきYAMLの文法
コメント
コメントには #
を使用します。コメントは一行で書くこともできますし、3行目のようにインラインコメントとして入力することができますが、コメントはその行の最後まで有効です。また複数行のコメントアウトはできないので#
を該当の範囲だけ入力する必要があります。
# コメント1
# コメント2
key: value # コメント3
インデントとスペース
YAMLではインデントが重要です。インデントにはスペースを使用しタブは使用しません。各レベルのインデントは、階層構造を表現します。
example:
- item1
- item2
データタイプ(スカラー、シーケンス、マップ)
YAMLを理解する際にここが一番の肝となる部分かなと思います。スカラー、シーケンス、マップを理解して、表記に慣れましょう。
# スカラー
string: "文字列"
number: 123
boolean: true
# シーケンス(配列)
fruits:
- apple
- banana
- cherry
# マップ(key-value型のデータでディクショナリーと同じ)
person:
name: John Doe
age: 30
データタイプの注意点
YAMLでハイフンあり、ハイフンなしの違いに少し混乱されている方もいるかもしれません。下記のYAMLを見てください。パターン1とパターン2-1・2-2は異なるデータタイプで、パターン2-1とパターン2-2は同じデータタイプです。
# パターン1
fruits1:
- apple
- banana
- cherry
# パターン2-1
fruits2-1:
- apple
banana
cherry
# パターン2-2
fruits2-2:
- apple banana cherry
これを確認するためにJSONに変換してみます。パターン1は3つの要素からなるリストになっていますが、パターン2-1と2-2は3つの単語+スペースを含む文字列として1つの要素からなるリストになっていることがわかります。
ちなみにJSONはコメント入力ができないので表示されていません。
{
"fruits1": [
"apple",
"banana",
"cherry"
],
"fruits2-1": [
"apple banana cherry"
],
"fruits2-2": [
"apple banana cherry"
]
}
特殊な記法
複数行の文字列を扱う場合は|(パイプ)
を使用します。
# 複数行
multiline: |
これは
複数行の
文字列です
重複する記述を避けるため、記述の再利用方法を説明します。&
の記述はアンカー(呼び出し元のデータ)、<<: *
の記述はエイリアス(呼び出し先ぼ場所)と呼ばれ、このアンカーとエイリアスを利用した記述の再利用方法をリファレンスと言います。
下記のリファレンス1-1とリファレンス1-2は同じ内容を示しています。
# リファレンス1-1
default: &default
name: John Doe
user1:
<<: *default
age: 25
# リファレンス1-2
default:
name: John Doe
user1:
name: John Doe
age: 25
下記のリファレンス2-1とリファレンス2-2も同じ内容を示しています。リファレンス2-1ではhostを再定義(9行目、14行目)することでリファレンスデータの上書きを図っています。
# リファレンス2-1
defaults: &defaults
adapter: postgres
host: localhost
development:
database: dev_db
<<: *defaults
host: 192.168.1.5
test:
database: test_db
<<: *defaults
host: 192.168.1.8
# リファレンス2-2
defaults: &defaults
adapter: postgres
host: localhost
development:
database: dev_db
<<: *defaults
host: 192.168.1.5
test:
database: test_db
<<: *defaults
host: 192.168.1.8
トラブルシューティング
YAMLを記述する際に出くわすエラーはほとんど下の2点になるかと思います。エラーにならないよう、タブとインデントの混在、データタイプを理解した記述を心がけましょう!
- インデントエラー
インデントの不一致が原因で発生するエラーです。適切なインデントを確認して修正しましょう。 - データタイプのミスマッチ
キーや値が適切なデータタイプでない場合に発生するエラーです。正しいデータタイプを使用していることを確認しましょう。
もしYAMLの文法で迷ったらこちらの公式ドキュメントで確認してみてくださいね。
実際のYAMLを解説
それでは実際のYAMLを見ていきます。構造把握のポイントは一番左のインデントからセクションを把握していくこと、リファレンスがある場合は落ち着いて参照元と参照先を確認することです。
下記のYAMLファイルは、Docker Composeを使って4つのサービス(web
, db
, app1
, app2
)を定義しています。db_data
ボリュームと my-predefined-network
ネットワークも設定されています。さらに、アンカーとエイリアスを使って環境変数のリストを複数のサービス間で再利用しています。この方法により、重複を避けてYAMLファイルの可読性とメンテナンス性を向上させています。
version: '3.8'
services:
web:
image: nginx
ports:
- "80:80"
environment:
- NGINX_HOST=localhost
- NGINX_PORT=80
db:
image: postgres
environment:
POSTGRES_DB: mydatabase
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
networks:
default:
external:
name: my-predefined-network
# アンカーとエイリアスの使用例
common_env: &common_env
- TZ=UTC
- LANG=en_US.UTF-8
services:
app1:
image: myapp1
environment: *common_env
app2:
image: myapp2
environment: *common_env
まとめ
本記事ではYAMLの文法とDockerComposeの読み解き方について解説しました。なんとなく扱えてしまうのでなあなあになっていた文法の理解が少しでも進んだのであればうれしいなと思います!YAMLの文法に早く慣れて、IaCの設定がスムーズになることを祈っています!