curlとjqを用いた堅牢なAPI死活監視とレスポンス検証の自動化

Tech

{ “style”: “Technical/SRE-focused”, “density”: “High”, “tone”: “Professional/Instructional”, “elements”: [“Mermaid”, “Robust Shell Scripting”, “Systemd Integration”] } 本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。

curlとjqを用いた堅牢なAPI死活監視とレスポンス検証の自動化

【導入と前提】

REST APIの正常性を定期監視し、特定のJSONフィールド値に基づいた精緻な異常検知と自動復旧フローへの橋渡しを実現します。

  • OS: GNU/Linux (Ubuntu/RHEL/Debian)

  • ツール: curl (7.60+), jq (1.6+)

【処理フローと設計】

graph TD
A["Start: API Request"] --> B{"HTTP Status Check"}
B -->|200 OK| C["JSON Payload Validation"]
B -->|Non-200| D["Error Handling / Retry"]
C -->|Match| E["Success / Update Metric"]
C -->|Mismatch| F["Alert / Log Error"]
D --> G[Finish]
E --> G
F --> G
  1. APIリクエスト: curlでHTTPステータスコードとレスポンスボディを分離して取得。

  2. ステータス判定: HTTP層でのエラー(4xx/5xx)を即座にハンドリング。

  3. JSON検証: jqを用いて、期待するキーの存在や値の範囲を評価。

  4. 結果出力: 標準出力および終了コードを通じて、後続の監視システム(systemd等)へ通知。

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

1. 監視用bashスクリプト (check_api.sh)

#!/usr/bin/env bash

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


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


# set -o pipefail: パイプライン内のエラーを適切に拾う

set -euo pipefail

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

trap 'rm -f /tmp/api_res_$$' EXIT

readonly API_URL="${1:-https://api.example.com/v1/health}"
readonly EXPECTED_STATUS="UP"

echo "[INFO] Checking API: ${API_URL}"

# curlの実行


# -s: 進捗非表示, -S: エラー表示, -f: 404等でエラー終了


# -L: リダイレクト追従, --retry: ネットワーク一時エラー時の再試行


# -w: 出力フォーマット指定(末尾にステータスコードを付与)

response=$(curl -sSL --retry 3 --max-time 10 -w "\n%{http_code}" "${API_URL}" || true)

# レスポンスとステータスコードの分離

body=$(echo "${response}" | sed '$d')
http_code=$(echo "${response}" | tail -n1)

# HTTPステータスコードの検証

if [[ "${http_code}" != "200" ]]; then
    echo "[ERROR] API returned HTTP ${http_code}" >&2
    exit 1
fi

# jqによるJSON内部バリデーション


# -e: フィルタ結果が false/null の場合に終了コード1を返す

if ! echo "${body}" | jq -e ".status == \"${EXPECTED_STATUS}\"" > /dev/null; then
    echo "[ERROR] Invalid API status value or malformed JSON" >&2
    echo "Response: ${body}" >&2
    exit 1
fi

echo "[SUCCESS] API is healthy."
exit 0

2. systemdによる定期実行設定

/etc/systemd/system/api-health-check.service:

[Unit]
Description=API Health Check Service
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/check_api.sh https://api.example.com/status

# 秘密情報の漏洩防止(必要に応じて)


# Environment=API_TOKEN=xxxx

/etc/systemd/system/api-health-check.timer:

[Unit]
Description=Run API Health Check every 5 minutes

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

[Install]
WantedBy=timers.target

【検証と運用】

正常系の確認

スクリプトを直接実行し、終了コードを確認します。

./check_api.sh https://api.example.com/health
echo $?  # 0 であれば正常

ログ確認(systemd経由)

定期実行の結果やエラー詳細は journalctl で一元管理されます。

# サービス実行履歴の確認

journalctl -u api-health-check.service -f

# エラーメッセージのみを抽出

journalctl -u api-health-check.service -p err

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

  1. パイプラインの終了コード: set -o pipefail を忘れると、curl が失敗しても jq に空文字が渡され、不適切な評価が行われる可能性があります。

  2. 認証情報の漏洩: APIトークンをコマンドライン引数で渡すと ps コマンドで見えてしまうため、環境変数(Environment)や設定ファイル経由での読み込みを検討してください。

  3. jqのバージョン差異: 古い jq (1.5未満) では -e フラグの挙動が一部異なる場合があります。可能な限り最新のバイナリを利用してください。

  4. プロキシ設定: 企業内ネットワークでは http_proxy 環境変数が curl に影響するため、--noproxy オプションの活用が必要な場合があります。

【まとめ】

運用の冪等性と堅牢性を維持するために、以下の3点を徹底してください。

  1. Exit Codeの厳格な管理: HTTP層とビジネスロジック層(JSON内容)の両方で非ゼロの終了コードを返すこと。

  2. リソースの自動破棄: trap を用いて一時ファイルや子プロセスを確実にクリーンアップすること。

  3. 再試行戦略の内製: 一時的なネットワーク瞬断でアラートを飛ばさないよう、curl--retry オプションを活用すること。

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

コメント

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