YAMLとは?基本の書き方と使い方を初心者向けに解説

プログラミング・IT

サーバー設定やDocker、Kubernetesなどの構成管理をしていると、よく目にする「YAML(ヤムル)」というファイル。

こんな経験はありませんか?

  • 「YAMLファイルを編集してって言われたけど、何これ?」
  • 「インデントがずれただけでエラーになる…」
  • 「JSONと何が違うの?」
  • 「書き方のルールがよくわからない」

実は、YAMLはとてもシンプルで読みやすい形式です。

この記事でわかること:

  • YAMLの基本概念と特徴
  • JSONやXMLとの違い
  • 実際に使える書き方の基本
  • よくあるエラーと対処法
  • 実際のプロジェクトでの活用例

この記事を読めば、YAMLを恐れることなく、自信を持って編集・作成できるようになります!

スポンサーリンク

YAMLとは何か?【基礎知識編】

YAMLの定義と由来

YAMLは**「YAML Ain’t Markup Language」**(YAMLはマークアップ言語じゃない)の再帰的頭字語です。

歴史と発展:

  • 2001年:Clark Evans、Ingy döt Net、Oren Ben-Kikiによって開発開始
  • 設計目標:人間が読みやすく、すべてのプログラミング言語でアクセス可能
  • 現在のバージョン:YAML 1.2(2009年リリース、現在も標準)

YAMLの主な特徴

特徴説明メリット
人間可読性インデントで構造を表現直感的に理解しやすい
軽量余計な記号が少ないファイルサイズが小さい
コメント対応#でコメント記述可能ドキュメント化しやすい
データタイプ豊富文字列、数値、配列、オブジェクトなど複雑なデータ構造も表現可能
言語非依存多くのプログラミング言語でサポート汎用性が高い

YAMLが使われる主な場面

1. 設定ファイル

# アプリケーション設定例
app:
  name: "MyApplication"
  version: "1.2.3"
  debug: true
  database:
    host: "localhost"
    port: 5432
    name: "mydb"

2. インフラ構成管理

# Docker Compose例
version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
  db:
    image: postgres:13
    environment:
      POSTGRES_DB: mydb

3. CI/CDパイプライン

# GitHub Actions例
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run tests
        run: npm test

YAMLと他の形式の比較

YAML vs JSON vs XML

同じデータの表現比較

YAML:

person:
  name: "田中太郎"
  age: 30
  skills:
    - "JavaScript"
    - "Python"
    - "Docker"
  contact:
    email: "tanaka@example.com"
    phone: "090-1234-5678"

JSON:

{
  "person": {
    "name": "田中太郎",
    "age": 30,
    "skills": [
      "JavaScript",
      "Python",
      "Docker"
    ],
    "contact": {
      "email": "tanaka@example.com",
      "phone": "090-1234-5678"
    }
  }
}

XML:

<person>
  <name>田中太郎</name>
  <age>30</age>
  <skills>
    <skill>JavaScript</skill>
    <skill>Python</skill>
    <skill>Docker</skill>
  </skills>
  <contact>
    <email>tanaka@example.com</email>
    <phone>090-1234-5678</phone>
  </contact>
</person>

比較表

項目YAMLJSONXML
可読性★★★★★☆★☆☆
記述量★★★★★☆★☆☆
コメント
パース速度★☆☆★★★★☆☆
Web API★☆☆★★★★★☆
設定ファイル★★★★★☆★☆☆

使い分けの指針

YAMLを選ぶべき場面

  • 設定ファイル:アプリケーション、インフラ設定
  • ドキュメント:APIドキュメント、仕様書
  • 人間が編集:手動で変更する可能性が高い

JSONを選ぶべき場面

  • API通信:REST APIのリクエスト/レスポンス
  • Webアプリ:JavaScript との親和性
  • パフォーマンス重視:高速なパースが必要

XMLを選ぶべき場面

  • レガシーシステム:既存システムとの互換性
  • 厳密な検証:XML Schemaによる厳密なバリデーション
  • 複雑な構造:名前空間、属性が必要

YAMLの基本文法【詳細解説】

1. 基本的なデータ型

スカラー値(単一の値)

# 文字列
name: "田中太郎"
title: プロジェクトマネージャー  # 引用符なしでもOK

# 数値
age: 30
price: 1299.99
scientific: 1.23e10

# 真偽値
active: true
completed: false
enabled: yes     # true と同じ
disabled: no     # false と同じ

# null値
middle_name: null
nickname: ~      # null と同じ

# 日付
birth_date: 1990-12-25
timestamp: 2023-01-01T10:00:00Z

複数行文字列

# 改行を保持(|記号)
description: |
  これは複数行の
  説明文です。
  改行が保持されます。

# 改行を空白に変換(>記号)
summary: >
  これは長い文章を
  複数行に分けて書いた場合、
  実際は一行になります。

# インデントを制御
code: |2
    def hello():
        print("Hello, World!")

2. コレクション(配列とオブジェクト)

配列(リスト)

# 基本的な配列
fruits:
  - apple
  - orange
  - banana

# インライン形式
colors: [red, green, blue]

# 複雑なオブジェクトの配列
users:
  - name: "Alice"
    role: "admin"
    active: true
  - name: "Bob"
    role: "user"
    active: false

# 入れ子の配列
matrix:
  - [1, 2, 3]
  - [4, 5, 6]
  - [7, 8, 9]

オブジェクト(辞書)

# 基本的なオブジェクト
person:
  name: "田中太郎"
  age: 30
  city: "東京"

# インライン形式
coordinates: {x: 10, y: 20}

# 入れ子のオブジェクト
company:
  name: "サンプル株式会社"
  address:
    zip: "100-0001"
    prefecture: "東京都"
    city: "千代田区"
    street: "千代田1-1-1"
  departments:
    - name: "開発部"
      members: 15
    - name: "営業部"
      members: 10

3. 高度な機能

アンカーとエイリアス(参照)

# アンカーの定義(&記号)
defaults: &default_settings
  timeout: 30
  retry_count: 3
  debug: false

# エイリアスで参照(*記号)
development:
  <<: *default_settings
  debug: true

production:
  <<: *default_settings
  timeout: 60

# 結果的に以下と同じ:
# development:
#   timeout: 30
#   retry_count: 3
#   debug: true
# production:
#   timeout: 60
#   retry_count: 3
#   debug: false

マージキー

# 複数の設定をマージ
server_defaults: &server
  memory: "512MB"
  cpu: 1

database_defaults: &database
  engine: "postgresql"
  version: "13"

app_server:
  <<: [*server, *database]
  name: "app-server"
  port: 8080

明示的なデータ型指定

# 文字列として明示
version: !!str 1.2
quote: !!str "true"

# 整数として明示
count: !!int "42"

# 浮動小数点として明示
price: !!float 19.99

# バイナリデータ
image: !!binary |
  R0lGODlhPQBEAPeoAJosM//AwO/AwHVYZ/z595kzAP/s7P+goOXMv8+fhw/v739/f+8PD98fH/8mJl+fn/9ZWb8/PzWlwv///6wWGbImAPgTEMImIN9gUFCEm/gDALULDN8PAD6atYdCTX

実践的なYAMLの書き方

1. Docker Compose の実例

# docker-compose.yml
version: '3.8'

services:
  # Webアプリケーション
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://user:password@db:5432/myapp
    depends_on:
      - db
      - redis
    volumes:
      - ./logs:/app/logs
    networks:
      - app-network

  # データベース
  db:
    image: postgres:13
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - app-network

  # Redis
  redis:
    image: redis:6-alpine
    networks:
      - app-network

  # リバースプロキシ
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/ssl:ro
    depends_on:
      - web
    networks:
      - app-network

volumes:
  postgres_data:

networks:
  app-network:
    driver: bridge

2. Kubernetes の実例

# kubernetes-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
  labels:
    app: web-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web-app
  template:
    metadata:
      labels:
        app: web-app
    spec:
      containers:
      - name: web
        image: myapp:latest
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: "production"
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: database-url
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
  name: web-app-service
spec:
  selector:
    app: web-app
  ports:
  - protocol: TCP
    port: 80
    targetPort: 3000
  type: ClusterIP

3. GitHub Actions の実例

# .github/workflows/ci.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  NODE_VERSION: '16'
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [14, 16, 18]
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
    
    - name: Setup Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run linting
      run: npm run lint
    
    - name: Run tests
      run: npm test
    
    - name: Run coverage
      run: npm run coverage
    
    - name: Upload coverage reports
      uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
    
    - name: Log in to Container Registry
      uses: docker/login-action@v2
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    
    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v4
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=sha
    
    - name: Build and push Docker image
      uses: docker/build-push-action@v4
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    
    steps:
    - name: Deploy to production
      run: |
        echo "Deploying to production..."
        # デプロイスクリプトの実行

よくあるエラーと対処法

1. インデント関連のエラー

問題:インデントの不一致

❌ 間違った例:

person:
  name: "田中"
    age: 30  # インデントが深すぎる
  city: "東京"

✅ 正しい例:

person:
  name: "田中"
  age: 30
  city: "東京"

問題:タブとスペースの混在

❌ 間違った例:

config:
  database:  # スペース2個
	host: localhost  # タブ文字(見た目は同じだがエラー)

✅ 正しい例:

config:
  database:
    host: localhost  # すべてスペース

2. データ型関連のエラー

問題:意図しない型変換

❌ 問題のある例:

version: 1.2.0  # 数値として解釈される
port: 008080    # 8進数として解釈される可能性
enabled: yes    # 真偽値として解釈される

✅ 明示的な型指定:

version: "1.2.0"  # 文字列として明示
port: "008080"    # 文字列として明示
enabled: "yes"    # 文字列として明示

# または
version: !!str 1.2.0
port: !!str 008080
enabled: !!str yes

3. 文字列関連のエラー

問題:特殊文字のエスケープ

❌ 問題のある例:

message: Hello "World"!  # 引用符が混在
path: C:\Users\name      # バックスラッシュの問題

✅ 正しいエスケープ:

message: 'Hello "World"!'  # シングルクォートで囲む
# または
message: "Hello \"World\"!"  # エスケープ

path: "C:\\Users\\name"    # バックスラッシュをエスケープ
# または
path: 'C:\Users\name'      # シングルクォートで囲む

4. 構造関連のエラー

問題:重複キー

❌ 問題のある例:

config:
  host: localhost
  port: 3000
  host: example.com  # 重複キー(上書きされる)

✅ 正しい構造:

config:
  primary_host: localhost
  backup_host: example.com
  port: 3000

YAMLの検証とツール

1. オンライン検証ツール

主要なYAML検証サイト

  • YAML Lint(yamllint.com):基本的な構文チェック
  • YAML Validator:詳細なエラー表示
  • JSON to YAML:形式変換

2. エディタとIDE

Visual Studio Code

// settings.json での設定
{
  "yaml.validate": true,
  "yaml.hover": true,
  "yaml.completion": true,
  "yaml.schemas": {
    "https://json.schemastore.org/docker-compose.json": "docker-compose*.yml",
    "kubernetes": "*.k8s.yml"
  }
}

推奨拡張機能:

  • YAML Language Support
  • Kubernetes Support
  • Docker Compose Support

3. コマンドラインツール

yamllint のインストールと使用

# インストール
pip install yamllint

# 基本的な検証
yamllint myfile.yml

# 設定ファイルを使用
yamllint -c .yamllint myfile.yml

# 設定ファイル例(.yamllint)
extends: default
rules:
  line-length:
    max: 120
  indentation:
    spaces: 2
  comments:
    min-spaces-from-content: 1

yq(YAML processor)

# インストール
brew install yq  # macOS
# または
wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64

# 基本的な使用例
yq eval '.services.web.ports' docker-compose.yml
yq eval '.spec.replicas = 5' deployment.yml
yq eval 'select(.kind == "Service")' k8s-manifest.yml

実際のプロジェクトでの活用例

1. アプリケーション設定管理

# config/app.yml
app:
  name: "MyApplication"
  version: "2.1.0"
  environment: "production"

server:
  host: "0.0.0.0"
  port: 8080
  timeout: 30

database:
  primary:
    host: "${DB_HOST:-localhost}"
    port: "${DB_PORT:-5432}"
    database: "${DB_NAME:-myapp}"
    username: "${DB_USER:-user}"
    password: "${DB_PASSWORD}"
  
  readonly:
    host: "${DB_READONLY_HOST}"
    port: "${DB_READONLY_PORT:-5432}"
    database: "${DB_NAME:-myapp}"
    username: "${DB_READONLY_USER}"
    password: "${DB_READONLY_PASSWORD}"

cache:
  redis:
    host: "${REDIS_HOST:-localhost}"
    port: "${REDIS_PORT:-6379}"
    password: "${REDIS_PASSWORD}"
    db: 0

logging:
  level: "${LOG_LEVEL:-info}"
  format: "json"
  outputs:
    - type: "console"
    - type: "file"
      path: "/var/log/app.log"
      max_size: "100MB"
      max_age: "7d"

features:
  user_registration: true
  email_verification: true
  two_factor_auth: false
  analytics: true

external_services:
  email:
    provider: "sendgrid"
    api_key: "${SENDGRID_API_KEY}"
  
  payment:
    provider: "stripe"
    public_key: "${STRIPE_PUBLIC_KEY}"
    secret_key: "${STRIPE_SECRET_KEY}"
    webhook_secret: "${STRIPE_WEBHOOK_SECRET}"

2. CI/CDパイプライン設定

# .gitlab-ci.yml
stages:
  - validate
  - test
  - build
  - deploy

variables:
  DOCKER_REGISTRY: registry.gitlab.com
  DOCKER_IMAGE: $DOCKER_REGISTRY/$CI_PROJECT_PATH
  KUBECONFIG: /tmp/kubeconfig

# 共通設定をアンカーで定義
.docker_template: &docker_template
  image: docker:20.10.16
  services:
    - docker:20.10.16-dind
  before_script:
    - echo $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY

.kubectl_template: &kubectl_template
  image: bitnami/kubectl:latest
  before_script:
    - echo "$KUBE_CONFIG" | base64 -d > $KUBECONFIG

# バリデーション
yaml_lint:
  stage: validate
  image: python:3.9-alpine
  before_script:
    - pip install yamllint
  script:
    - yamllint .
  only:
    - merge_requests
    - main

dockerfile_lint:
  stage: validate
  image: hadolint/hadolint:latest-debian
  script:
    - hadolint Dockerfile
  only:
    - merge_requests
    - main

# テスト
unit_test:
  stage: test
  image: node:16-alpine
  cache:
    paths:
      - node_modules/
  script:
    - npm ci
    - npm run test:unit
  coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

integration_test:
  stage: test
  image: node:16-alpine
  services:
    - postgres:13
    - redis:6-alpine
  variables:
    DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/test"
    REDIS_URL: "redis://redis:6379"
  script:
    - npm ci
    - npm run test:integration

# ビルド
build_image:
  <<: *docker_template
  stage: build
  script:
    - docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA .
    - docker tag $DOCKER_IMAGE:$CI_COMMIT_SHA $DOCKER_IMAGE:latest
    - docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
    - docker push $DOCKER_IMAGE:latest
  only:
    - main

# デプロイ
deploy_staging:
  <<: *kubectl_template
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE:$CI_COMMIT_SHA -n staging
    - kubectl rollout status deployment/myapp -n staging
  environment:
    name: staging
    url: https://staging.example.com
  only:
    - main

deploy_production:
  <<: *kubectl_template
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE:$CI_COMMIT_SHA -n production
    - kubectl rollout status deployment/myapp -n production
  environment:
    name: production
    url: https://example.com
  when: manual
  only:
    - main

3. Infrastructure as Code(Ansible)

# playbook.yml
---
- name: Web Server Setup
  hosts: webservers
  become: true
  vars:
    app_name: myapp
    app_user: deploy
    app_port: 3000
    nginx_port: 80
    ssl_enabled: true
    
  tasks:
    - name: Update system packages
      apt:
        update_cache: true
        upgrade: safe
      tags: [system]

    - name: Install required packages
      apt:
        name:
          - nginx
          - nodejs
          - npm
          - certbot
          - python3-certbot-nginx
        state: present
      tags: [packages]

    - name: Create application user
      user:
        name: "{{ app_user }}"
        system: true
        shell: /bin/bash
        home: "/var/www/{{ app_name }}"
        create_home: true
      tags: [user]

    - name: Create application directories
      file:
        path: "{{ item }}"
        state: directory
        owner: "{{ app_user }}"
        group: "{{ app_user }}"
        mode: '0755'
      loop:
        - "/var/www/{{ app_name }}"
        - "/var/www/{{ app_name }}/logs"
        - "/var/www/{{ app_name }}/shared"
      tags: [directories]

    - name: Deploy application
      unarchive:
        src: "{{ app_archive_url }}"
        dest: "/var/www/{{ app_name }}"
        remote_src: true
        owner: "{{ app_user }}"
        group: "{{ app_user }}"
      notify: restart app
      tags: [deploy]

    - name: Install Node.js dependencies
      npm:
        path: "/var/www/{{ app_name }}"
        production: true
      become_user: "{{ app_user }}"
      tags: [deploy]

    - name: Configure systemd service
      template:
        src: systemd.service.j2
        dest: "/etc/systemd/system/{{ app_name }}.service"
      notify:
        - reload systemd
        - restart app
      tags: [service]

    - name: Configure Nginx
      template:
        src: nginx.conf.j2
        dest: "/etc/nginx/sites-available/{{ app_name }}"
      notify: restart nginx
      tags: [nginx]

    - name: Enable Nginx site
      file:
        src: "/etc/nginx/sites-available/{{ app_name }}"
        dest: "/etc/nginx/sites-enabled/{{ app_name }}"
        state: link
      notify: restart nginx
      tags: [nginx]

    - name: Obtain SSL certificate
      command: >
        certbot --nginx
        --non-interactive
        --agree-tos
        --email "{{ ssl_email }}"
        -d "{{ domain_name }}"
      when: ssl_enabled
      tags: [ssl]

  handlers:
    - name: reload systemd
      systemd:
        daemon_reload: true

    - name: restart app
      systemd:
        name: "{{ app_name }}"
        state: restarted
        enabled: true

    - name: restart nginx
      systemd:
        name: nginx
        state: restarted
        enabled: true

ベストプラクティス

1. 読みやすさの向上

適切なコメント

# 良い例:目的と注意事項を記載
# データベース接続設定
# 注意: パスワードは環境変数から取得
database:
  host: "${DB_HOST}"
  port: 5432
  # 本番環境では読み書き分離
  read_replicas:
    - "${DB_READ_REPLICA_1}"
    - "${DB_READ_REPLICA_2}"

# 悪い例:自明なコメント
database:
  host: localhost  # ホスト名
  port: 5432       # ポート番号

一貫したインデント

# 推奨:2スペースで統一
services:
  web:
    image: nginx
    ports:
      - "80:80"
  
  app:
    build: .
    environment:
      - NODE_ENV=production

# 避ける:インデント幅の混在
services:
    web:          # 4スペース
        image: nginx
  app:            # 2スペース
    build: .

2. 保守性の向上

環境変数の活用

# config.yml
app:
  name: "${APP_NAME:-MyApp}"
  version: "${APP_VERSION:-1.0.0}"
  debug: "${DEBUG:-false}"

database:
  url: "${DATABASE_URL}"
  pool_size: "${DB_POOL_SIZE:-10}"
  timeout: "${DB_TIMEOUT:-30}"

# デフォルト値の設定例
defaults: &defaults
  timeout: 30
  retry_count: 3
  log_level: "info"

development:
  <<: *defaults
  debug: true
  log_level: "debug"

production:
  <<: *defaults
  timeout: 60
  retry_count: 5

バリデーション用スキーマ

# JSON Schema for validation
# config-schema.yml
$schema: "http://json-schema.org/draft-07/schema#"
type: object
required:
  - app
  - database
properties:
  app:
    type: object
    required:
      - name
      - version
    properties:
      name:
        type: string
        minLength: 1
      version:
        type: string
        pattern: "^\\d+\\.\\d+\\.\\d+$"
      debug:
        type: boolean
        default: false
  
  database:
    type: object
    required:
      - url
    properties:
      url:
        type: string
        format: uri
      pool_size:
        type: integer
        minimum: 1
        maximum: 100
        default: 10

3. セキュリティ考慮事項

機密情報の管理

# ❌ 悪い例:機密情報をハードコード
database:
  host: "prod-db.example.com"
  username: "admin"
  password: "super_secret_password123"  # 危険!

# ✅ 良い例:環境変数や外部シークレット管理
database:
  host: "${DB_HOST}"
  username: "${DB_USERNAME}"
  password: "${DB_PASSWORD}"

# Kubernetes Secretsを使用
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:
  username: YWRtaW4=  # base64エンコード
  password: cGFzc3dvcmQ=

ファイル権限の設定

# 設定ファイルの適切な権限設定
chmod 600 config.yml        # 所有者のみ読み書き可能
chmod 644 docker-compose.yml # 一般的な設定ファイル
chmod 400 secrets.yml       # 所有者のみ読み取り可能

高度なYAMLテクニック

1. 動的設定の生成

テンプレートエンジンとの組み合わせ

# Jinja2テンプレート例
# config.yml.j2
app:
  name: "{{ app_name }}"
  replicas: {{ replicas | default(3) }}
  
{% if environment == "production" %}
resources:
  limits:
    cpu: "1000m"
    memory: "1Gi"
  requests:
    cpu: "500m"
    memory: "512Mi"
{% else %}
resources:
  limits:
    cpu: "500m"
    memory: "512Mi"
  requests:
    cpu: "100m"
    memory: "128Mi"
{% endif %}

{% for service in services %}
  {{ service.name }}:
    image: "{{ service.image }}"
    port: {{ service.port }}
{% endfor %}

2. 条件分岐とループの実現

Helm Chart での条件分岐

# values.yml
replicaCount: 3
autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100

ingress:
  enabled: true
  className: "nginx"
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"

# deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "myapp.fullname" . }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  
  template:
    spec:
      containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        {{- if .Values.ingress.enabled }}
        ports:
        - name: http
          containerPort: 80
          protocol: TCP
        {{- end }}

3. 大規模プロジェクトでの分割管理

ファイル分割パターン

# docker-compose.yml (メインファイル)
version: '3.8'

include:
  - compose.services.yml
  - compose.networks.yml
  - compose.volumes.yml

# compose.services.yml
services:
  web:
    extends:
      file: common-services.yml
      service: web-base
    environment:
      - NODE_ENV=production

# common-services.yml
version: '3.8'
services:
  web-base:
    build: .
    ports:
      - "3000"
    volumes:
      - ./logs:/app/logs

Kustomize での設定管理

# base/kustomization.yml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - deployment.yml
  - service.yml
  - configmap.yml

# overlays/production/kustomization.yml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

bases:
  - ../../base

patchesStrategicMerge:
  - deployment-patch.yml

images:
  - name: myapp
    newTag: v1.2.3

replicas:
  - name: myapp
    count: 5

トラブルシューティング

1. パフォーマンス問題

大きなYAMLファイルの最適化

# ❌ 非効率な例
users:
  - name: "user1"
    permissions:
      - read
      - write
  - name: "user2"
    permissions:
      - read
      - write
  # 数千のユーザー...

# ✅ 効率的な例(アンカー使用)
permissions: &default_permissions
  - read
  - write

users:
  - name: "user1"
    permissions: *default_permissions
  - name: "user2"
    permissions: *default_permissions

ストリーミング処理

# Python でのストリーミング YAML パース
import yaml

def process_large_yaml(file_path):
    with open(file_path, 'r') as file:
        # ストリーミングで処理
        for document in yaml.safe_load_all(file):
            process_document(document)
            
def process_document(doc):
    # 各ドキュメントを個別に処理
    print(f"Processing: {doc.get('name', 'Unknown')}")

2. 互換性問題

YAML バージョン間の差異

# YAML 1.1 と 1.2 の違い
yes_value: yes      # 1.1: true, 1.2: "yes"
no_value: no        # 1.1: false, 1.2: "no"
octal_value: 0123   # 1.1: 83, 1.2: 123

# 明示的な型指定で回避
boolean_yes: !!bool "yes"
boolean_no: !!bool "no"
string_yes: !!str "yes"
integer_octal: !!int "0o123"  # 8進数の正しい書き方

3. デバッグテクニック

YAML構造の可視化

# yq を使った構造確認
yq eval '.' config.yml

# 特定のパスの確認
yq eval '.services.web.environment' docker-compose.yml

# 型情報を含む出力
yq eval -j '.' config.yml | jq '.'

段階的な確認

# デバッグ用の段階的設定
debug:
  level: 1  # 1=basic, 2=detailed, 3=verbose

# レベル1: 基本情報のみ
basic_config:
  app_name: "myapp"
  version: "1.0"

# レベル2: 詳細設定追加
detailed_config:
  <<: *basic_config
  database:
    host: "localhost"
    port: 5432

# レベル3: 全設定
verbose_config:
  <<: *detailed_config
  logging:
    level: "debug"
    output: "file"

まとめ:YAMLを効果的に活用しよう

YAMLは、適切に使用することで、設定管理やインフラ構成を大幅に改善できる強力なツールです。

重要なポイントのおさらい

YAML の特徴:

  • 人間可読性:直感的で理解しやすい
  • 構造化データ:複雑な設定も表現可能
  • コメント対応:ドキュメント化が容易
  • 環境変数対応:動的な設定管理

書き方のポイント:

  • 一貫したインデント(2スペース推奨)
  • 適切なコメント(目的と注意事項)
  • アンカーとエイリアスで重複を削減
  • 環境変数で柔軟性を確保

エラー回避のコツ:

  • yamllintでの事前チェック
  • エディタの支援機能を活用
  • 型の明示的指定で予期しない変換を防止
  • 段階的なテストで問題を早期発見

実際の業務での活用

DevOps エンジニア:

  • Docker Compose、Kubernetes マニフェスト
  • CI/CDパイプライン設定
  • Infrastructure as Code

開発者:

  • アプリケーション設定
  • API仕様書(OpenAPI)
  • テストデータ定義

システム管理者:

  • サーバー設定管理
  • 監視設定
  • バックアップスクリプト設定

コメント

タイトルとURLをコピーしました