YAML のリストを書くとき、ハイフンを mapping のキーと同じ位置に置く例と、2 スペース下げる例があります。
items:
- apple
- bananaitems:
- apple
- bananaこの二つは、YAML 1.2.2 では同じ mapping と sequence として解釈できます。ただし、ここから「YAML のリストではインデントが不要」と一般化するのは正確ではありません。YAML の block style はインデントでスコープを表し、ハイフンは sequence の各要素を表します。両方が構造の決定に関わります。
実務では、構文として許されるか、同じデータ構造になるか、チームで読みやすいかを分けて判断する必要があります。
結論:単純な mapping の値ならどちらも正しい
items: の値として block sequence を置く場合、ハイフンをキーと同じ列に置く書き方と、さらにインデントする書き方は、どちらも有効です。
| 書き方 | 構文 | 実務上の特徴 |
|---|---|---|
| キーとハイフンを同じ列に置く | 有効 | 短く、YAML emitter や kubectl -o yaml などの出力で見かける |
| ハイフンを 2 スペース下げる | 有効 | mapping の値であることが視覚的に分かりやすい |
構文上の正誤だけなら、どちらか一方を排除する理由はありません。ただし、同じファイルやリポジトリで両方を無秩序に混在させると、差分レビュー時に構造の変更と整形だけの変更を見分けにくくなります。プロジェクトとして一つの形式に揃える方が扱いやすくなります。
YAML はインデントと記号の両方で構造を表す
YAML 1.2.2 の仕様では、block collection はインデントでスコープを表します。そのうえで、sequence entry はハイフンと空白(- )、mapping entry はキーに続くコロンと空白(: )で表します。
- インデント:どの node がどの親に属するかを表す
- ハイフン: sequence の要素であることを表す
- コロン: mapping の key / value を区切る
元の説明である「キーはインデントが重要で、リストはハイフンが重要」という理解では足りません。sequence も親子関係や兄弟関係をインデントで判断します。ハイフンがあれば、どの位置に置いても同じ sequence になるわけではありません。
なぜインデントなしでも同じ構造になるのか
YAML の仕様は、人間がハイフン自体をインデントの一部として認識することを考慮しています。そのため、block mapping の値として sequence を置く BLOCK-OUT の文脈では、sequence を通常より一段少なくインデントできる規則があります。
次の二つを Ruby の YAML parser などで読み込むと、どちらも {"items" => ["apple", "banana"]} に相当する構造になります。
# ハイフンをキーと同じ列に置く
items:
- apple
- banana# ハイフンを 2 スペース下げる
items:
- apple
- bananaこれは、インデントが無関係だからではありません。この位置にある block sequence に対して、仕様が一段浅い表記を許可しているためです。
インデントを変えると構造が変わる例
実務で危険なのは、構文エラーになる場合だけではありません。YAML としては有効なまま、意図と異なる構造になることがあります。
次の YAML では、colors は apple と同じ mapping の要素です。
items:
- name: apple
colors:
- red
- green一方、colors を行頭へ戻すと、構文エラーにはならず、items と同じ階層の別キーになります。
items:
- name: apple
colors:
- red
- greenこの違いは、YAML parser が検出してくれるとは限りません。どちらも有効な YAML だからです。Kubernetes manifest なら field の位置が変わり、Ansible playbook なら task、vars、handlers などの所属が変わる可能性があります。
兄弟要素は同じインデントに揃える
同じ sequence に属するハイフンは、同じ列に揃える必要があります。次のように一つだけずらすと、別の階層として解釈されるか、parser が構文エラーを返します。
# 不正な例
items:
- apple
- bananaYAML 1.2.2 は、各 node を親より深くインデントし、兄弟 node を同じインデントレベルに置くことを求めています。何スペース使うかは表現上の選択ですが、同じ階層で揃っていることが重要です。
タブをインデントに使わない
YAML のインデントにはスペースを使います。タブはエディターによって表示幅が異なるため、YAML 1.2.2 ではインデントへの使用が認められていません。
エディターで Tab キーを使う場合も、入力結果をスペースへ変換する設定にします。見た目では揃っていても、スペースとタブが混在すると parser や lint で失敗する原因になります。
Ansible と Kubernetes では 2 スペースを基本にする
Ansible の YAML syntax では、同じリストの要素を同じインデントレベルに置き、ハイフンと空白で始める形が説明されています。Ansible Lint の YAML rule は Prettier と互換性のある整形を既定とし、インデント違反を検出します。
Kubernetes manifest でも、手書きする場合は 2 スペース単位で sequence を mapping の値として下げる形式が読みやすいと考えます。
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80kubectl get -o yaml などの生成結果では、containers: とハイフンを同じ列に置く形式が出力されることがあります。生成物をそのまま比較・再生成するなら、ツールの形式を維持する方が不要な差分を減らせます。人間が継続的に編集するファイルなら、2 スペース下げる形式へ統一する方が親子関係を追いやすくなります。
正しい書き方より、正をどこに置くかを決める
YAML の仕様が複数の表記を許すことと、プロジェクト内で自由に書いてよいことは同じではありません。運用では、次の順序で方針を決めると整理しやすくなります。
- 生成ファイルなら、生成元ツールの出力を正とする
- 既存リポジトリなら、すでに採用されている形式に合わせる
- 新規の手書きファイルなら、2 スペース単位で sequence も下げる
yamllint、Ansible Lint、Prettier などを CI に組み込み、書き手ごとの差を減らす- 整形だけの変更と、データ構造を変える変更を同じ commit に混ぜない
重要なのは、好みの優劣を決めることではありません。どのツールが出力し、誰が編集し、どの形式を CI が受け入れるのかという境界を決めることです。
参考情報
参考書籍
書籍
YAML、Ansible、Kubernetes を学ぶための参考書
YAML の構造を、Ansible playbook や Kubernetes manifest の実例とともに確認するための参考書籍です。価格や在庫はリンク先で確認してください。
Amazon で見るこのリンクは Amazon アソシエイトリンクです。
あわせて読みたい:
- Podman の Kubernetes YAML
Podman でコンテナや Pod の構成を Kubernetes YAML として扱う記事です。 - Kubernetes マニフェストの apiVersion を理解する
YAML の書式だけでなく、Kubernetes API が manifest をどう解釈するかを確認します。
まとめ
YAML では、mapping の値として単純な block sequence を置く場合、キーとハイフンを同じ列に置く書き方と、ハイフンを 2 スペース下げる書き方のどちらも有効です。
ただし、これはリストのインデントが構文上無関係という意味ではありません。インデントは親子関係とスコープを表し、ハイフンは sequence entry を表します。位置を変えると、構文エラーにならないままデータ構造だけが変わることもあります。
生成物は生成元の形式を維持し、人が管理する Ansible playbook や Kubernetes manifest は 2 スペース単位で揃え、lint と formatter で統一するのが実用的です。議論すべきなのは 2 スペースの好みではなく、どの形式をプロジェクトの正として管理するかです。
