<p><style_prompt_metadata>
{
“style”: “Technical/SRE-focused”,
“density”: “High”,
“tone”: “Professional/Instructional”,
“elements”: [“Mermaid”, “Robust Shell Scripting”, “Systemd Integration”]
}
</style_prompt_metadata>
本記事は<strong>Geminiの出力をプロンプト工学で整理した業務ドラフト(未検証)</strong>です。</p>
<h1 class="wp-block-heading">curlとjqを用いた堅牢なAPI死活監視とレスポンス検証の自動化</h1>
<h2 class="wp-block-heading">【導入と前提】</h2>
<p>REST APIの正常性を定期監視し、特定のJSONフィールド値に基づいた精緻な異常検知と自動復旧フローへの橋渡しを実現します。</p>
<ul class="wp-block-list">
<li><p><strong>OS</strong>: GNU/Linux (Ubuntu/RHEL/Debian)</p></li>
<li><p><strong>ツール</strong>: <code>curl</code> (7.60+), <code>jq</code> (1.6+)</p></li>
</ul>
<h2 class="wp-block-heading">【処理フローと設計】</h2>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
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
</pre></div>
<ol class="wp-block-list">
<li><p><strong>APIリクエスト</strong>: <code>curl</code>でHTTPステータスコードとレスポンスボディを分離して取得。</p></li>
<li><p><strong>ステータス判定</strong>: HTTP層でのエラー(4xx/5xx)を即座にハンドリング。</p></li>
<li><p><strong>JSON検証</strong>: <code>jq</code>を用いて、期待するキーの存在や値の範囲を評価。</p></li>
<li><p><strong>結果出力</strong>: 標準出力および終了コードを通じて、後続の監視システム(systemd等)へ通知。</p></li>
</ol>
<h2 class="wp-block-heading">【実装:堅牢な自動化スクリプト】</h2>
<h3 class="wp-block-heading">1. 監視用bashスクリプト (<code>check_api.sh</code>)</h3>
<div class="codehilite">
<pre data-enlighter-language="generic">#!/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
</pre>
</div>
<h3 class="wp-block-heading">2. systemdによる定期実行設定</h3>
<p><code>/etc/systemd/system/api-health-check.service</code>:</p>
<div class="codehilite">
<pre data-enlighter-language="generic">[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
</pre>
</div>
<p><code>/etc/systemd/system/api-health-check.timer</code>:</p>
<div class="codehilite">
<pre data-enlighter-language="generic">[Unit]
Description=Run API Health Check every 5 minutes
[Timer]
OnCalendar=*:0/5
Persistent=true
[Install]
WantedBy=timers.target
</pre>
</div>
<h2 class="wp-block-heading">【検証と運用】</h2>
<h3 class="wp-block-heading">正常系の確認</h3>
<p>スクリプトを直接実行し、終了コードを確認します。</p>
<div class="codehilite">
<pre data-enlighter-language="generic">./check_api.sh https://api.example.com/health
echo $? # 0 であれば正常
</pre>
</div>
<h3 class="wp-block-heading">ログ確認(systemd経由)</h3>
<p>定期実行の結果やエラー詳細は <code>journalctl</code> で一元管理されます。</p>
<div class="codehilite">
<pre data-enlighter-language="generic"># サービス実行履歴の確認
journalctl -u api-health-check.service -f
# エラーメッセージのみを抽出
journalctl -u api-health-check.service -p err
</pre>
</div>
<h2 class="wp-block-heading">【トラブルシューティングと落とし穴】</h2>
<ol class="wp-block-list">
<li><p><strong>パイプラインの終了コード</strong>: <code>set -o pipefail</code> を忘れると、<code>curl</code> が失敗しても <code>jq</code> に空文字が渡され、不適切な評価が行われる可能性があります。</p></li>
<li><p><strong>認証情報の漏洩</strong>: APIトークンをコマンドライン引数で渡すと <code>ps</code> コマンドで見えてしまうため、環境変数(<code>Environment</code>)や設定ファイル経由での読み込みを検討してください。</p></li>
<li><p><strong>jqのバージョン差異</strong>: 古い <code>jq</code> (1.5未満) では <code>-e</code> フラグの挙動が一部異なる場合があります。可能な限り最新のバイナリを利用してください。</p></li>
<li><p><strong>プロキシ設定</strong>: 企業内ネットワークでは <code>http_proxy</code> 環境変数が <code>curl</code> に影響するため、<code>--noproxy</code> オプションの活用が必要な場合があります。</p></li>
</ol>
<h2 class="wp-block-heading">【まとめ】</h2>
<p>運用の冪等性と堅牢性を維持するために、以下の3点を徹底してください。</p>
<ol class="wp-block-list">
<li><p><strong>Exit Codeの厳格な管理</strong>: HTTP層とビジネスロジック層(JSON内容)の両方で非ゼロの終了コードを返すこと。</p></li>
<li><p><strong>リソースの自動破棄</strong>: <code>trap</code> を用いて一時ファイルや子プロセスを確実にクリーンアップすること。</p></li>
<li><p><strong>再試行戦略の内製</strong>: 一時的なネットワーク瞬断でアラートを飛ばさないよう、<code>curl</code> の <code>--retry</code> オプションを活用すること。</p></li>
</ol>
{
“style”: “Technical/SRE-focused”,
“density”: “High”,
“tone”: “Professional/Instructional”,
“elements”: [“Mermaid”, “Robust Shell Scripting”, “Systemd Integration”]
}
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
curlとjqを用いた堅牢なAPI死活監視とレスポンス検証の自動化
【導入と前提】
REST APIの正常性を定期監視し、特定のJSONフィールド値に基づいた精緻な異常検知と自動復旧フローへの橋渡しを実現します。
【処理フローと設計】
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
APIリクエスト: curlでHTTPステータスコードとレスポンスボディを分離して取得。
ステータス判定: HTTP層でのエラー(4xx/5xx)を即座にハンドリング。
JSON検証: jqを用いて、期待するキーの存在や値の範囲を評価。
結果出力: 標準出力および終了コードを通じて、後続の監視システム(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
【トラブルシューティングと落とし穴】
パイプラインの終了コード: set -o pipefail を忘れると、curl が失敗しても jq に空文字が渡され、不適切な評価が行われる可能性があります。
認証情報の漏洩: APIトークンをコマンドライン引数で渡すと ps コマンドで見えてしまうため、環境変数(Environment)や設定ファイル経由での読み込みを検討してください。
jqのバージョン差異: 古い jq (1.5未満) では -e フラグの挙動が一部異なる場合があります。可能な限り最新のバイナリを利用してください。
プロキシ設定: 企業内ネットワークでは http_proxy 環境変数が curl に影響するため、--noproxy オプションの活用が必要な場合があります。
【まとめ】
運用の冪等性と堅牢性を維持するために、以下の3点を徹底してください。
Exit Codeの厳格な管理: HTTP層とビジネスロジック層(JSON内容)の両方で非ゼロの終了コードを返すこと。
リソースの自動破棄: trap を用いて一時ファイルや子プロセスを確実にクリーンアップすること。
再試行戦略の内製: 一時的なネットワーク瞬断でアラートを飛ばさないよう、curl の --retry オプションを活用すること。
コメント