Docker ComposeでDB接続情報を各サービスに毎回コピペしていて、1箇所修正するたびに直し漏れが発生していました。アンカーとマージキーの存在を知ってからは、共通設定を1箇所に集約できるようになり、書き漏れの事故が明確に減りました。

アンカー(&)と参照(*)の基本

YAMLのアンカー・参照・マージキーの関係を示す図

図1: &で定義した値を、*とマージキー<<で再利用する

アンカー(&名前はノード(値)に名前を付ける機能で、参照(*名前はそのアンカーが指す値をそのままコピーして展開する機能です。同じ値を何度も書く代わりに、1箇所で定義して使い回せます。

YAML — アンカーと参照の基本
default_timeout: &timeout 30

api_client:
  connect_timeout: *timeout
  read_timeout: *timeout

&timeout で値 30timeout という名前を付け、*timeout でその値を参照しています。結果として connect_timeoutread_timeout は両方とも 30 になります。値そのものだけでなく、マッピングやシーケンス全体にアンカーを付けることもできます。

マージキー(<<)による結合

マッピング全体を再利用しつつ、一部だけ上書きしたい場合に使うのがマージキー(<<です。アンカーで定義したマッピングを丸ごと展開し、同じキーがあれば自分の定義で上書きします。

YAML — マージキーで環境ごとの設定を作る
defaults: &defaults
  adapter: postgres
  host: localhost
  pool: 5

development:
  <<: *defaults
  database: dev_db

production:
  <<: *defaults
  database: prod_db
  host: db.prod.internal   # defaultsのhostを上書き
  pool: 20                 # defaultsのpoolを上書き

production&defaults の3項目をすべて引き継ぎつつ、hostpool だけを独自の値で上書きしています。同じ設定を何度も書き写す必要がなくなり、修正漏れも防げます。

⚠️ マージキーはYAML 1.1由来の慣習的な拡張構文

<< はYAML本体のコア仕様(YAML 1.2)には含まれておらず、多くの実装が慣習として対応している拡張構文という位置づけです。使用する言語のYAMLパーサーが対応しているか、事前に確認してください(Python の PyYAML、Ruby の Psych など主要な実装は概ね対応しています)。

複数ドキュメント(---, ...)

1つのファイルに複数の独立したYAMLドキュメントをまとめたい場合、---(3つのハイフン)で区切ります。ドキュメントの終端を明示したい場合は ...(3つのピリオド)を使いますが、省略されることも多いです。

YAML — 複数ドキュメントの例(Kubernetesマニフェストで頻出)
apiVersion: v1
kind: Service
metadata:
  name: web-service
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-deployment
spec:
  replicas: 3

この記法はKubernetesのマニフェストファイルで特に頻繁に使われます。1つの kubectl apply -f コマンドで、複数のリソース定義をまとめてクラスタに適用できるためです。プログラムからパースする場合、多くのYAMLライブラリには「複数ドキュメントを順番に読み込む」専用の関数が用意されています(PythonのPyYAMLなら yaml.safe_load_all())。

フロースタイル(インライン記法)

ここまで見てきたインデントベースの書き方をブロックスタイルと呼びます。一方でYAMLには、JSONのように {}[] を使って1行で書くフロースタイルも用意されています。

YAML — ブロックスタイルとフロースタイルの対比
# ブロックスタイル
person:
  name: Alice
  age: 30
  tags:
    - admin
    - staff

# 同じ内容をフロースタイルで書いた場合
person: { name: Alice, age: 30, tags: [admin, staff] }

フロースタイルはJSONとの親和性が高く、実際ほとんどのJSONファイルはそのまま有効なYAMLとして読み込めます(JSONはYAMLのフロースタイルのサブセットに近い関係にあります)。短い設定を1行にまとめたいときや、他形式からの変換結果を扱うときに使われますが、可読性の観点から長い構造はブロックスタイルで書くのが一般的です。

特殊文字のエスケープと複数行文字列

コロンやハイフンなど、YAMLの記法として意味を持つ文字を文字列の一部として使いたい場合は、クォートで囲みます。シングルクォートとダブルクォートには挙動の違いがあります。

クォート特徴
なし(プレーン)最も一般的。ただし特殊文字を含む場合や数値・真偽値と誤解されそうな文字列には使えない
シングルクォート '...'エスケープシーケンスを解釈しない。'自体を含めるには''と2つ重ねる
ダブルクォート "..."\n\tなどのエスケープシーケンスを解釈できる
YAML — クォートが必要になる代表例
time_format: "12:30:00"        # コロンを含むためクォート必須
country_code: "NO"              # 真偽値と誤解されるのを防ぐ
path: 'C:\Users\name'           # シングルクォートならバックスラッシュはそのまま
message: "Line1\nLine2"         # ダブルクォートでエスケープシーケンスを解釈

複数行の長いテキスト(説明文やスクリプト本体など)を書きたい場合は、ブロックスカラーと呼ばれる |(リテラル)または >(フォールド)を使います。

YAML — 複数行文字列(| と >)
# | : 改行をそのまま保持する
script: |
  echo "start"
  npm install
  npm run build

# > : 改行をスペースに変換して1行の文章として畳み込む
description: >
  これは複数行にわたって書かれた
  長い説明文ですが、実際には
  スペース区切りの1行として扱われます。

💡 使い分けの目安

コマンドの羅列やコードなど、改行そのものに意味がある場合は | を、長い説明文のように改行を気にせず読めればよい場合は > を使うと覚えると迷いません。

まとめ

記法役割
&名前 / *名前値に名前を付けて再利用する(アンカー/参照)
<<: *名前マッピングを丸ごと展開し、一部だけ上書きする(マージキー)
---1ファイルに複数のドキュメントをまとめる区切り
{ } / [ ]JSON風に1行で書くフロースタイル
'...' / "..."特殊文字を含む文字列を明示的に区切る
| / >複数行文字列(改行を保持/畳み込む)

次の章では…

PART 05(最終回)では、ここまでの記法を前提に、チームで記述ルールを統一する考え方と、yamllintルールのカスタマイズ、CI(GitHub Actions)への組み込み方を解説し、シリーズ全体をまとめます。

→ PART 05 — 記述ルールとベストプラクティスへ