
YAMLバリデーター — デプロイを壊す前にYAMLエラーを修正する
📷 Lukas from Pexels / PexelsYAMLバリデーター — デプロイを壊す前にYAMLエラーを修正する
YAMLの空白の敏感さや独特のクォーティングルールは本番環境での障害を引き起こします。よくあるYAMLのミス、プッシュ前の検証方法、JSONよりYAMLを選ぶべきタイミングを学びましょう。
最初に検証することを教えてくれたデプロイ
金曜日の午後 — これが起きるには最悪のタイミングです。Kubernetesのデプロイメントが2日間レビュー中で、最終承認が下りた後、kubectl applyコマンドがすべてを止めるエラーを吐き出しました:
error: error parsing deployment.yaml: error converting YAML to JSON: yaml: line 34: mapping values are not allowed in this context
34行目。200行のマニフェストの中で。問題の原因はこれでした:
env:
- name: DATABASE_URL
value: postgres://user:password@host:5432/db
問題ないように見えますよね?いいえ、違います。値の文字列内のコロン — user:password — がYAMLのマッピング構文として部分的に解釈されていました。修正は些細なことでした:
env:
- name: DATABASE_URL
value: "postgres://user:password@host:5432/db"
クォート1組。30分のデバッグ。教訓:重要なものに触れる前にYAMLを検証する。
YAMLが本当にトリッキーな理由
YAMLには評判の問題があります。シンプルに見えます — ブラケットも波括弧もなく、インデントされたキーと値のペアだけです。そのシンプルさは本物ですが、隠れた代償があります:YAMLのルールは、特にエッジケースについては、推論するのが驚くほど複雑です。
空白は構文です。 ほとんどの言語では、空白は装飾的です。YAMLでは、キーの前のスペース数がドキュメントツリーでの位置を定義します。2スペースは1レベルのネストを意味し、4スペースは2レベルを意味します。これを間違えると、パーサーはエラーを出すか、意図と異なる構造をサイレントに作成します。「サイレントに異なる構造を作成する」ケースが危険なものです。
タブは絶対にダメです。 これは常に人々を引っかけます。エディターがTabキーを押したときにタブを挿入したり、タブを使ったブログ記事からYAMLをペーストしたり、別の設定のエディターを使っている人から設定を引き継いだりすることがあります。YAMLパーサーはfound character that cannot start any tokenのようなエラーでインデントに使われたタブを拒否します。
型推測は積極的です。 YAMLは型を推測することで親切にしようとします。これはよく知られた落とし穴を作ります:
# これらはYAML 1.1(ほとんどのツールが使うバージョン)では文字列ではありません
version: 1.0 # 文字列ではなく浮動小数点
enabled: yes # 文字列"yes"ではなくブーリアンtrue
id: 08 # 8進数8...またはパースエラー
country: NO # ブーリアンfalse(ノルウェーのISOコード!)
これらを文字列にする必要がある場合は、クォートしなければなりません。常に。
複数行文字列は非直感的です。 YAMLには2つの複数行スカラースタイルがあります — リテラルブロック(|)と折り畳みブロック(>)。リテラルは改行を保持し、折り畳みは単一の改行をスペースに変換します。両方ともトレーリング改行を保持するか削除するかを制御するチョンピングインジケーター(|+、|-)があります。
最もよくあるYAMLエラー(例付き)
1. コロンを含む未クォートの文字列
# 壊れている — コロンが暗黙のマッピングを作成
message: Error: connection refused
# 修正済み
message: "Error: connection refused"
2. スペースの代わりにタブ
# 壊れている("name"の前にタブ)
server:
name: prod-01 # ここにタブ文字 — エラーになります
# 修正済み(スペース)
server:
name: prod-01
3. 一貫性のないインデント
# 壊れている — "port"は4スペースのインデント、"host"は2スペース
database:
host: localhost
port: 5432 # 間違い — "port"が"host"の子になります
# 修正済み
database:
host: localhost
port: 5432
4. 未クォートの特殊文字
# 壊れている — #はコメントを開始するため、"value"は失われます
description: This is important # not a comment here
# 実際には問題ない — インラインコメントは有効なYAMLですが、#を値に含めたい場合:
description: "This is important # still part of the string"
# 壊れている — &と*はアンカー/エイリアス構文
label: "AT&T" # 問題なし
label: AT&T # 問題ないかもしれないが、リスクあり — クォートするべき
5. 重複キー
# 壊れている — ほとんどのパーサーで2番目の"host"が最初のものをサイレントに上書き
database:
host: localhost
port: 5432
host: prod.example.com # 重複 — 悪い
6. 不正なブーリアンとnullの値
# これらはすべてYAML 1.1でブーリアンtrueです:
enabled: true
enabled: True
enabled: yes
enabled: on
# これらはすべてnullです:
value: ~
value: null
value: Null
# 文字列の"yes"または"null"が必要な場合は、クォートします:
status: "yes"
type: "null"
7. アンカー/エイリアスの間違い
defaults: &defaults
timeout: 30
retries: 3
production:
<<: *defaults # マージキー — 有効だが紛らわしい
timeout: 60 # アンカー値を上書き
staging:
<<: *defaults
timeout: 15
YAMLバリデーターの使い方
toolboxhubs.comのYAMLバリデーターは、エラーがパイプラインに到達する前にキャッチするワークフロー向けに設計されています。
ステップ1 — YAMLを貼り付ける。 設定ファイルの全内容 — docker-compose.yml、.github/workflows/deploy.yml、values.yamlなど — をコピーして入力パネルに貼り付けます。
ステップ2 — 検証を実行する。 バリデーターはすぐにYAMLをパースし、行番号を含む最初の構文エラーを報告します。修正して再実行します。
ステップ3 — パース出力を確認する。 エラーをキャッチするだけでなく、バリデーターはパースされた構造をツリーとして表示します。ここで論理エラーをキャッチできます — キーが構文的には正しい位置にあるが、ネストレベルが間違っている場合などです。
ステップ4 — 型を確認する。 文字列が文字列として、ブーリアンがブーリアンとして、数値が数値として表示されているかに注意を払います。
フォーマット間で変換する必要がある場合、JSON to YAMLコンバーターは両者間の変換を処理し、JSONフォーマッターは両方のフォーマットで作業する際に役立ちます。
YAML vs JSON — どちらを選ぶか
YAMLを使う場合:
- 人間が定期的にファイルを編集する(CI設定、Kubernetesマニフェスト、Ansibleプレイブック)
- コメントが重要 — YAMLは
#コメントをサポートし、JSONはサポートしない - ネストされた構造の視覚的なノイズを減らしたい
- 設定が主に静的で機械生成ではない
JSONを使う場合:
- ファイルがコードで生成されコードで読まれる — 人間はほとんど触れない
- 厳格な型保証が必要
- JSONを期待するAPIを扱っている
- 可能な限りシンプルなツールが必要
特定ツールでのYAML
GitHub Actions
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: npm test
env:
NODE_ENV: test
DATABASE_URL: ${{ secrets.DATABASE_URL }}
${{ }}式構文はYAML構文ではなく、YAMLパース前にActionsによって評価されます。
Docker Compose
services:
app:
image: node:20-alpine
ports:
- "3000:3000"
environment:
- NODE_ENV=production
volumes:
- ./src:/app/src:ro
depends_on:
db:
condition: service_healthy
"3000:3000"はクォートされています — コロンがそれを必要とします。
Kubernetesマニフェスト
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
app: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:latest
ports:
- containerPort: 8080
spec.template.specのダブルネストは頻繁に人々を引っかけます。内側のspecはPod仕様で、外側はDeployment仕様です。
YAMLをエラーなく書くためのヒント
1. バリデーターだけでなくリンターを使う。 バリデーターはYAMLが構文的に有効かどうかを教えます。yamllintのようなリンターは、一貫したインデント、末尾スペース、行の長さなども強制します。
2. エディターを適切に設定する。 .ymlファイルと.yamlファイルには2スペースインデントでスペース(タブではなく)を使うようにエディターを設定します。
3. 文字列を防御的にクォートする。 文字列値に:、#、{、}、[、]、*、&、または!が含まれている場合はクォートします。ブーリアンまたはnullとして誤解される可能性がある場合もクォートします。
4. プッシュ前に検証する。 pre-commitフックにYAML検証を追加します:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/adrienverge/yamllint
rev: v1.35.1
hooks:
- id: yamllint
args: [-d, relaxed]
5. アンカーを使うがドキュメント化する。 アンカーは重複を減らしますが、認知的オーバーヘッドを追加します。&defaultsと<<: *defaultsを使う場合は、アンカーに何が含まれるかを説明するコメントを追加します。
6. ノルウェー問題に注意する。 YAML 1.1では、2文字の文字列NOはブーリアンのfalseとしてパースされます。ノルウェーのISO 3166-1 alpha-2国コードはNOです。国コードやyes/noのようなステータス文字列は無条件にクォートします。
7. パーサーのYAMLバージョンを把握する。 PythonのPyYAMLはデフォルトで1.1を使います。Goのgopkg.in/yaml.v3は1.2を実装します。JavaScriptのjs-yamlもデフォルトで1.2です。
まとめ
YAMLは現代のインフラツールの主要な設定言語です — Kubernetes、GitHub Actions、Docker Compose、Ansible、そしてほとんどのCI/CDシステムはその上に構築されています。そのため、その失敗モードを知ることは学術的な興味だけでなく、本当に重要です。
実用的なワークフローはシンプルです:プッシュ前、特にデプロイパイプラインに触れるものについては、YAMLバリデーターに設定を貼り付けます。10秒かかるだけで、金曜日の午後に200行のマニフェストの謎めいた行番号を追うことになるエラーのクラスをキャッチできます。
フォーマット間で設定を変換する場合、JSON to YAMLが変換をクリーンに処理し、JSONフォーマッターは方程式のJSON側を検証するのに役立ちます。まず検証する習慣をつけましょう — 将来の自分がそれに感謝するでしょう。