APIヘルスチェックの堅牢化:curlとjqによる自動検証とsystemd統合

Tech
{
  "status": "work_in_progress",
  "component": "SRE_Automation_Toolkit",
  "tools": ["curl", "jq", "bash", "systemd"],
  "reliability_level": "Draft_Unverified",
  "security_focus": ["Error_Handling", "Sensitive_Data_Protection"]
}

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

APIヘルスチェックの堅牢化:curlとjqによる自動検証とsystemd統合

【導入と前提】

REST APIの応答整合性を自動検証し、異常検知時に安全に停止・通知するSRE向けスクリプトの構築手法。

  • 前提条件: Linux OS, curl (7.70.0+), jq (1.6+) がインストールされていること。

【処理フローと設計】

graph TD
A["Start: Timer/Cron"] --> B["curl: API Request"]
B --> C{"HTTP Status 200?"}
C -- No --> D["Error Log & Exit"]
C -- Yes --> E["jq: Parse JSON Body"]
E --> F{"Validate Business Logic"}
F -- Invalid --> G["Alert: JSON Schema/Value Error"]
F -- Valid --> H["End: Success Update"]
  1. リクエストフェーズ: curl のリトライ機能を使い、一時的なネットワークエラーを許容。

  2. パースフェーズ: jq の終了コード (-e) を利用して、期待するフィールドの存在を確認。

  3. 終了フェーズ: set -euo pipefail により、パイプラインの途中で発生したエラーを確実に捕捉。

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

1. API検証スクリプト (api_check.sh)

#!/bin/bash


# ==============================================================================


# API Response Validator


# Description: REST APIのレスポンスを検証し、異常があれば非ゼロで終了する。


# ==============================================================================

set -euo pipefail

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


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


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

readonly API_URL="https://api.example.com/v1/health"
readonly EXPECTED_VERSION="1.2.0"
readonly TMP_FILE=$(mktemp /tmp/api_response.XXXXXX.json)

# 終了時に一時ファイルを確実に削除

trap 'rm -f "$TMP_FILE"' EXIT

echo "[INFO] Starting API check for $API_URL"

# 1. APIリクエスト実行


# -s: 進捗表示を非表示 (Silent)


# -S: エラー時はメッセージを表示 (Show error)


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


# --retry: 通信失敗時のリトライ回数


# -w: HTTPステータスコードを抽出

HTTP_STATUS=$(curl -sSL --retry 3 \
    -o "$TMP_FILE" \
    -w "%{http_code}" \
    "$API_URL")

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

if [[ "$HTTP_STATUS" != "200" ]]; then
    echo "[ERROR] HTTP Status $HTTP_STATUS received." >&2
    exit 1
fi

# 3. jqによるJSON整合性の検証


# -e: 条件に合致しない(nullやfalse)場合に終了コード 1 を返す


# -r: 出力からクォートを除去 (Raw output)

echo "[INFO] Validating JSON response..."
if ! jq -e ".status == \"ok\" and .version == \"$EXPECTED_VERSION\"" "$TMP_FILE" > /dev/null; then
    echo "[ERROR] JSON validation failed. Unexpected status or version." >&2
    cat "$TMP_FILE" >&2
    exit 1
fi

echo "[SUCCESS] API health check passed."

2. systemd タイマーによる定期実行 (api-check.timer)

# /etc/systemd/system/api-check.service

[Unit]
Description=API Health Check Service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/api_check.sh
User=nobody
Group=nogroup

# /etc/systemd/system/api-check.timer

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

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

[Install]
WantedBy=timers.target

【検証と運用】

正常系の確認

スクリプトを直接実行し、終了コードが 0 であることを確認します。

./api_check.sh
echo $?  # 0が表示されればOK

異常系のログ確認 (systemd)

APIがダウン、または期待しないJSONを返した場合は、journalctl で詳細を確認します。

# 失敗した直近のログを表示

journalctl -u api-check.service -n 50 --no-pager

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

  • パイプラインの罠: curl | jq と記述すると、curl が失敗(404など)しても jq 自体が正常に動作すれば、パイプ全体の終了コードが 0 になるリスクがあります。必ず set -o pipefail を使うか、-o オプションで一時ファイルに書き出してから検証してください。

  • 機密情報の露出: curl -v をデバッグで使う際、Authorization ヘッダーがログに残らないよう注意してください。本番環境では -sS を推奨します。

  • 一時ファイルの肥大化: mktemp で作成したファイルは trap で確実に消去します。OSの再起動まで残る /tmp を圧迫しない設計が重要です。

【まとめ】

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

  1. Fail-fastの徹底: set -euo pipefail をシェルスクリプトの「一丁目一番地」とする。

  2. 型と値の両面検証: HTTPコードだけでなく、jq を使ってビジネスロジック(期待するステータス値やバージョン)まで踏み込んで検証する。

  3. 副作用の最小化: trap によるクリーンアップと、systemd ユーザー権限(nobody推奨)による最小権限実行を組み合わせる。

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

コメント

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