META: [TITLE] JSON/YAML相互変換による設定ファイル動的生成の自動化パイプライン [SRE_LEVEL] Senior [TAGS] #SRE #DevOps #Automation #jq #yq #Bash #Systemd
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
外部API連携による設定ファイルの動的YAML生成とSystemd管理の自動化
【導入と前提】
APIから取得したJSONメタデータを、システムが要求するYAML形式へ安全に変換し、systemdによるライフサイクル管理までを自動化します。
前提条件:
OS: Linux (Ubuntu 22.04+ / RHEL 8+ 推奨)
ツール:
curl,jq(JSON処理),yq(YAML処理/v4以降),systemd
【処理フローと設計】
graph TD
A["外部API / JSONソース"] -->|curl| B("テンポラリJSON保存")
B -->|jq filter| C{"データ整形"}
C -->|yq conversion| D["プロダクションYAML設定"]
D -->|Validation| E["Systemd Service Reload"]
E -->|Success| F["一時ファイル削除"]
E -->|Failure| G["ロールバック/通知"]
このフローでは、データの取得から反映までをアトミックに実行します。中間ファイルに mktemp を使用することで、競合状態を防止し、yq による厳密なスキーマ検証を経てから本番環境へ配置します。
【実装:堅牢な自動化スクリプト】
#!/usr/bin/env bash
# ---------------------------------------------------------
# 設定ファイル動的生成スクリプト
# ---------------------------------------------------------
set -euo pipefail # エラーで停止、未定義変数禁止、パイプエラーの伝播
trap 'cleanup' EXIT # 終了時に一時ファイルを確実に削除
# 定数定義
API_ENDPOINT="https://api.example.com/v1/config"
DEST_CONFIG="/etc/myapp/config.yaml"
TMP_JSON=$(mktemp /tmp/config.XXXXXX.json)
TMP_YAML=$(mktemp /tmp/config.XXXXXX.yaml)
# クリーンアップ関数
cleanup() {
rm -f "$TMP_JSON" "$TMP_YAML"
}
echo "INFO: 設定の取得を開始します..."
# 1. リトライ付きでJSONを取得
# -s: 進捗非表示, -S: エラー表示, -f: HTTPエラー時に失敗, -L: リダイレクト追従
# --retry: 通信失敗時のリトライ回数
curl -sSfL --retry 3 "$API_ENDPOINT" -o "$TMP_JSON"
# 2. jqによるフィルタリングとyqによるYAML変換
# jq -r: 生の文字列を出力
# yq eval: プロパティの置換やフォーマット変換
cat "$TMP_JSON" | \
jq -r '.data | .env="production"' | \
yq eval -P > "$TMP_YAML"
# 3. 妥当性チェック(スキーマ検証の代用)
if ! yq eval 'has("database")' "$TMP_YAML" > /dev/null; then
echo "ERROR: 必須パラメータ 'database' が欠落しています。" >&2
exit 1
fi
# 4. アトミックな配置と権限設定
# sudo権限が必要な場合は、実行ユーザーに適切なsudoers設定が必要
sudo install -m 644 -o root -g root "$TMP_YAML" "$DEST_CONFIG"
# 5. Systemdユニットのリロード
if systemctl is-active --quiet myapp.service; then
echo "INFO: サービスの再読み込みを実行します..."
sudo systemctl reload myapp.service
fi
echo "SUCCESS: 設定ファイルの更新が完了しました。"
Systemd Timerによる定期実行(例)
/etc/systemd/system/config-sync.timer
[Unit] Description=Run config sync every 30 minutes [Timer] OnBootSec=5min OnUnitActiveSec=30min Unit=config-sync.service [Install] WantedBy=timers.target
【検証と運用】
正常系の確認:
スクリプトを手動実行し、
$DEST_CONFIGの中身が期待通りのYAML構造になっているか確認。journalctl -u config-sync.serviceで実行ログを確認。
エラー時のログ確認:
systemctl status config-sync.serviceで終了ステータスを確認。JSONが不正な場合、
jqが標準エラー出力に吐き出すパースエラーを確認。
【トラブルシューティングと落とし穴】
権限問題:
sudo installを使用していますが、自動化スクリプトを実行するユーザー(例:deploy-agent)には、特定のコマンド実行(systemctl reload等)をパスワードなしで許可するvisudo設定が必要です。環境変数の漏洩防止: APIキーなどをスクリプトに直書きせず、
exportされた環境変数や AWS Secrets Manager 等から注入してください。yqのバージョン互換性: Python版
yqと Go版yq(mikefarah/yq) は構文が異なります。本稿では主流の Go版 (v4) を前提としています。一時ファイルの放置:
set -eで停止してもtrapが実行されるよう設計していますが、ディスクフル等の極端な状況下では手動確認が必要です。
【まとめ】
運用の冪等性を維持するための3つのポイント:
アトミックな書き換え: 一時ファイルで生成・検証を終えてから
mvまたはinstallで一気に置換する。検証の強制: 変換直後に
yqやjqで必須キーの存在チェックをかけ、不完全な設定をデプロイしない。状態の可視化: 成功・失敗を標準出力/標準エラー出力に明確に分離して吐き出し、
systemd-journalで追跡可能にする。

