JSON/YAMLの相互変換による設定ファイル自動生成とデプロイの自動化

Tech

[META] { “style_prompt”: “professional_sre_technical_report”, “technical_focus”: [“json_yaml_conversion”, “jq_yq_automation”, “systemd_integration”, “shell_safety”], “language”: “ja” } [/META]

本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

JSON/YAMLの相互変換による設定ファイル自動生成とデプロイの自動化

【導入と前提】 API経由で取得した動的なJSONデータを、k8sや各種ミドルウェアが要求するYAML形式に変換・注入し、システム設定を自動更新する堅牢なパイプラインを構築します。

  • 前提環境: Linux OS (Bash 4.4+), jq, yq (mikefarah version), curl がインストールされていること。

【処理フローと設計】

graph TD
A["外部ソース JSON"] -->|curl/jq| B["中間データ抽出"]
B -->|yq evaluation| C["YAMLテンプレート結合"]
C -->|Validation| D["最終設定ファイル生成"]
D -->|Atomic Move| E["サービス再起動/リロード"]

外部リポジトリやAPIから取得したJSONを正規化し、構造を維持したままYAMLへ変換。整合性チェックを経て、アトミックな書き換えによりダウンタイムのリスクを最小化します。

【実装:堅牢な自動化スクリプト】

#!/usr/bin/env bash

# --- 安全のためのシェルの設定 ---

set -euo pipefail
IFS=$'\n\t'

# --- 変数定義 ---

SOURCE_URL="https://api.example.com/v1/config"
DEST_YAML="/etc/app/config.yaml"
TMP_DIR=$(mktemp -d)
TMP_JSON="${TMP_DIR}/source.json"
TMP_YAML="${TMP_DIR}/output.yaml"

# --- 終了時のクリーンアップ処理 ---

trap 'rm -rf "$TMP_DIR"' EXIT

echo "Starting configuration sync..."

# 1. 外部ソースからJSONを取得 (curlオプション: -s 静音, -f エラー時失敗, -L リダイレクト追従)

if ! curl -sfL "$SOURCE_URL" -o "$TMP_JSON"; then
    echo "Error: Failed to fetch JSON from $SOURCE_URL" >&2
    exit 1
fi

# 2. jqによるフィルタリングと正規化


# 必要なフィールドのみ抽出し、欠損値にはデフォルト値をセット

jq -e '.settings | {env: (.env // "prod"), version: .version}' "$TMP_JSON" > "${TMP_JSON}.filtered"

# 3. yqによるYAMLへの変換とテンプレート注入


# (yqオプション: -P 読みやすい形式で出力)

yq -P eval "${TMP_JSON}.filtered" > "$TMP_YAML"

# 4. 既存ファイルとの差分確認とバリデーション

if [ -f "$DEST_YAML" ] && diff -q "$DEST_YAML" "$TMP_YAML" > /dev/null; then
    echo "No changes detected. Skipping update."
    exit 0
fi

# 5. 安全なデプロイ (mvによるアトミックな更新)


# 事前にバックアップを取得することを推奨

cp "$DEST_YAML" "${DEST_YAML}.bak" || true
mv "$TMP_YAML" "$DEST_YAML"
chmod 644 "$DEST_YAML"

echo "Configuration updated successfully."

補足:systemdによる定期実行の自動化

このスクリプトを定期的に実行するためのタイマー設定例です。

/etc/systemd/system/config-sync.service

[Unit]
Description=Sync Config from JSON API
After=network-online.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/sync-config.sh
User=root

# ログをsystemd-cat経由で出力

StandardOutput=journal
StandardError=journal

/etc/systemd/system/config-sync.timer

[Unit]
Description=Run config sync every 15 minutes

[Timer]
OnCalendar=*:0/15
Persistent=true

[Install]
WantedBy=timers.target

【検証と運用】

  1. 正常系の確認:

    • systemctl start config-sync.service を手動実行し、$DEST_YAML が意図した構造で生成されているか確認します。

    • yq eval '.' /etc/app/config.yaml でYAMLの構文妥当性を検証します。

  2. エラーログの確認:

    • 実行失敗時は journalctl -u config-sync.service を参照。set -x をスクリプト冒頭に追加することで、詳細なデバッグトレースが可能です。

【トラブルシューティングと落とし穴】

  • yqのバージョン互換性: yq にはGo版(mikefarah)とPython版(kislyuk)が存在し、コマンド体系が全く異なります。本稿では主流のGo版を使用しています。

  • 権限問題: /etc 直下への書き込みには sudo が必要ですが、スクリプト内での sudo 多用は避け、systemdユニットの User= 指定や、適切なディレクトリ権限の付与で対応してください。

  • 一時ファイルの残存: trap 処理が確実に実行されるよう、kill -9 ではなく SIGTERM での停止を運用ルールとして徹底します。

【まとめ:運用の冪等性を維持するためのポイント】

  1. 差分チェックの実施: diff やチェックサム比較を行い、内容に変更がない場合はサービス再起動等の副作用を発生させないこと。

  2. 中間ファイルによる検証: 直接本番ファイルを加工せず、必ず一時ファイルで変換・バリデーションを完了させてからアトミックに置換すること。

  3. デフォルト値の定義: jq// 演算子などを活用し、APIレスポンスに欠損があっても設定ファイルが壊れない設計にすること。

ライセンス:本記事のテキスト/コードは特記なき限り CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。

コメント

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