JSON/YAML変換を核とした設定ファイルの自動生成と冪等性の担保

Tech

{ “expert_role”: “SRE / DevOps Engineer”, “focus”: “Automated Config Generation & JSON/YAML Processing”, “workflow”: “Research-First -> Safe Scripting (set -euo pipefail) -> Pipeline Design -> systemd Integration”, “tools”: [“jq”, “yq”, “curl”, “systemd”, “bash”], “integrity_check”: “Applied trap for cleanup, atomic file writes, and idempotent validation.” }

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

JSON/YAML変換を核とした設定ファイルの自動生成と冪等性の担保

【導入と前提】

API経由で取得したJSONメタデータをYAML形式のシステム設定へ変換し、検証を経て自動反映する堅牢なワークフローを構築します。

  • OS: GNU/Linux (Ubuntu 22.04 LTS / RHEL 9 動作確認)

  • 必須ツール:

    • jq (JSONプロセッサ)

    • yq (mikefarah/yq: YAMLプロセッサ)

    • curl (通信クライアント)

【処理フローと設計】

graph TD
A["API Endpoint"] -->|curl -sSfL| B["Raw JSON"]
B -->|jq filter| C["Structured JSON"]
C -->|yq eval| D["Candidate YAML"]
D -->|Validation| E{"Syntax Check"}
E -->|Success| F["Atomic Update /etc/..."]
E -->|Failure| G["Log Error & Trap"]
F -->|systemd trigger| H["Service Reload"]

入力されたJSONはフィルタリングを経て正規化され、YAML変換後にバリデーションを実施します。最終的なファイル配置はアトミック(原子性)を確保するため、一時ファイルからのリネーム操作で行います。

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

#!/usr/bin/env bash

# --- 安全な実行のための設定 ---

set -euo pipefail

# -e: エラー発生時に即座に終了


# -u: 未定義変数の参照時にエラー


# -o pipefail: パイプライン途中のエラーも検知

# --- 変数定義 ---

CONFIG_URL="https://api.example.com/v1/config"
TARGET_FILE="/etc/opt/myapp/config.yaml"
TMP_DIR=$(mktemp -d)
TMP_JSON="${TMP_DIR}/source.json"
TMP_YAML="${TMP_DIR}/candidate.yaml"

# --- 後処理のトラップ ---


# スクリプト終了時に(成功・失敗に関わらず)一時ファイルを削除

trap 'rm -rf "$TMP_DIR"' EXIT

echo "[INFO] 設定の同期を開始します..."

# 1. APIからJSON取得 (リトライ処理込み)


# -s: サイレント


# -S: エラー時に詳細を表示


# -f: HTTPエラー(404等)で終了コードを非ゼロにする


# -L: リダイレクトに追従

curl -sSfL --retry 3 --retry-delay 2 "$CONFIG_URL" -o "$TMP_JSON"

# 2. jqによる抽出と正規化


# -e: 抽出結果がnullまたはfalseなら終了コード1を返す

jq -e '.settings | .version = "1.0"' "$TMP_JSON" > "${TMP_JSON}.filtered"

# 3. yqによるYAML変換


# P: プロパティ形式を保持

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

# 4. バリデーション (例: YAML構文チェック)

if ! yq eval '.' "$TMP_YAML" > /dev/null; then
    echo "[ERROR] YAMLの構文チェックに失敗しました" >&2
    exit 1
fi

# 5. アトミックなファイル更新


# 既存ファイルと同じディレクトリ内でmvすることで、メタデータ破損を防ぐ

echo "[INFO] 設定ファイルを更新中..."
install -m 644 -o root -g root "$TMP_YAML" "${TARGET_FILE}.new"
mv "${TARGET_FILE}.new" "$TARGET_FILE"

# 6. systemdによるサービスリロード (必要に応じて)


# systemctl reload-or-restart myapp.service || true

echo "[SUCCESS] 同期完了"

systemd タイマー設定例

定期実行を確実に管理するため、cronではなくsystemd timerを推奨します。

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

[Unit]
Description=Sync Configuration from API

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

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

[Unit]
Description=Run config sync every hour

[Timer]
OnCalendar=hourly
RandomizedDelaySec=300
Persistent=true

[Install]
WantedBy=timers.target

【検証と運用】

  • 正常系確認: systemctl start config-sync.service を実行後、ls -l /etc/opt/myapp/config.yaml で更新日時と権限を確認。

  • ログ確認: journalctl -u config-sync.service -f で実行ログおよび標準エラー出力を追跡。

  • 差分確認: diff /etc/opt/myapp/config.yaml /path/to/backup で意図しない破壊的変更がないか目視確認。

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

  1. 権限問題: スクリプトが /etc 配下を書き換える場合、sudo または systemd ユニット上での User=root 設定が必須です。

  2. APIのレート制限: 短時間での頻繁な実行は API 429 エラーを招きます。systemd.timerRandomizedDelaySec を活用し、リクエストを分散させてください。

  3. 部分的な失敗: jq のフィルタリングで想定外のキーが欠落している場合、set -e により後続の YAML 生成を止め、不完全な設定ファイルがデプロイされるのを防ぎます。

  4. 環境変数の保護: APIキーが必要な場合は、スクリプト内にハードコードせず、EnvironmentFile= を用いて systemd から注入してください。

【まとめ】

運用の冪等性を維持するための3つのポイント:

  1. Atomic Write(原子性のある書き込み): > (リダイレクト) で直接ファイルを上書きせず、mv を使用して書き換え中のファイル参照を防ぐ。

  2. Pre-flight Validation(事前検証): ファイルを本番パスへ配置する前に、必ず yq 等でシンタックスチェックを行う。

  3. Declarative Management(宣言的管理): 手動の変更は一切行わず、常に API(ソース)を正としてスクリプト経由で状態を収束させる。

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

コメント

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