<pre data-enlighter-language="generic">
{
"status": "work_in_progress",
"component": "SRE_Automation_Toolkit",
"tools": ["curl", "jq", "bash", "systemd"],
"reliability_level": "Draft_Unverified",
"security_focus": ["Error_Handling", "Sensitive_Data_Protection"]
}
</pre>
<p>本記事は<strong>Geminiの出力をプロンプト工学で整理した業務ドラフト(未検証)</strong>です。</p>
<h1 class="wp-block-heading">APIヘルスチェックの堅牢化:curlとjqによる自動検証とsystemd統合</h1>
<h2 class="wp-block-heading">【導入と前提】</h2>
<p>REST APIの応答整合性を自動検証し、異常検知時に安全に停止・通知するSRE向けスクリプトの構築手法。</p>
<ul class="wp-block-list">
<li><strong>前提条件</strong>: Linux OS, <code>curl</code> (7.70.0+), <code>jq</code> (1.6+) がインストールされていること。</li>
</ul>
<h2 class="wp-block-heading">【処理フローと設計】</h2>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
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"]
</pre></div>
<ol class="wp-block-list">
<li><p><strong>リクエストフェーズ</strong>: <code>curl</code> のリトライ機能を使い、一時的なネットワークエラーを許容。</p></li>
<li><p><strong>パースフェーズ</strong>: <code>jq</code> の終了コード (<code>-e</code>) を利用して、期待するフィールドの存在を確認。</p></li>
<li><p><strong>終了フェーズ</strong>: <code>set -euo pipefail</code> により、パイプラインの途中で発生したエラーを確実に捕捉。</p></li>
</ol>
<h2 class="wp-block-heading">【実装:堅牢な自動化スクリプト】</h2>
<h3 class="wp-block-heading">1. API検証スクリプト (<code>api_check.sh</code>)</h3>
<div class="codehilite">
<pre data-enlighter-language="generic">#!/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."
</pre>
</div>
<h3 class="wp-block-heading">2. systemd タイマーによる定期実行 (<code>api-check.timer</code>)</h3>
<div class="codehilite">
<pre data-enlighter-language="generic"># /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
</pre>
</div>
<h2 class="wp-block-heading">【検証と運用】</h2>
<h3 class="wp-block-heading">正常系の確認</h3>
<p>スクリプトを直接実行し、終了コードが <code>0</code> であることを確認します。</p>
<div class="codehilite">
<pre data-enlighter-language="generic">./api_check.sh
echo $? # 0が表示されればOK
</pre>
</div>
<h3 class="wp-block-heading">異常系のログ確認 (systemd)</h3>
<p>APIがダウン、または期待しないJSONを返した場合は、<code>journalctl</code> で詳細を確認します。</p>
<div class="codehilite">
<pre data-enlighter-language="generic"># 失敗した直近のログを表示
journalctl -u api-check.service -n 50 --no-pager
</pre>
</div>
<h2 class="wp-block-heading">【トラブルシューティングと落とし穴】</h2>
<ul class="wp-block-list">
<li><p><strong>パイプラインの罠</strong>: <code>curl | jq</code> と記述すると、<code>curl</code> が失敗(404など)しても <code>jq</code> 自体が正常に動作すれば、パイプ全体の終了コードが <code>0</code> になるリスクがあります。必ず <code>set -o pipefail</code> を使うか、<code>-o</code> オプションで一時ファイルに書き出してから検証してください。</p></li>
<li><p><strong>機密情報の露出</strong>: <code>curl -v</code> をデバッグで使う際、<code>Authorization</code> ヘッダーがログに残らないよう注意してください。本番環境では <code>-sS</code> を推奨します。</p></li>
<li><p><strong>一時ファイルの肥大化</strong>: <code>mktemp</code> で作成したファイルは <code>trap</code> で確実に消去します。OSの再起動まで残る <code>/tmp</code> を圧迫しない設計が重要です。</p></li>
</ul>
<h2 class="wp-block-heading">【まとめ】</h2>
<p>運用の冪等性と堅牢性を維持するための3つのポイント:</p>
<ol class="wp-block-list">
<li><p><strong>Fail-fastの徹底</strong>: <code>set -euo pipefail</code> をシェルスクリプトの「一丁目一番地」とする。</p></li>
<li><p><strong>型と値の両面検証</strong>: HTTPコードだけでなく、<code>jq</code> を使ってビジネスロジック(期待するステータス値やバージョン)まで踏み込んで検証する。</p></li>
<li><p><strong>副作用の最小化</strong>: <code>trap</code> によるクリーンアップと、<code>systemd</code> ユーザー権限(nobody推奨)による最小権限実行を組み合わせる。</p></li>
</ol>
{
"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"]
リクエストフェーズ: curl のリトライ機能を使い、一時的なネットワークエラーを許容。
パースフェーズ: jq の終了コード (-e) を利用して、期待するフィールドの存在を確認。
終了フェーズ: 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つのポイント:
Fail-fastの徹底: set -euo pipefail をシェルスクリプトの「一丁目一番地」とする。
型と値の両面検証: HTTPコードだけでなく、jq を使ってビジネスロジック(期待するステータス値やバージョン)まで踏み込んで検証する。
副作用の最小化: trap によるクリーンアップと、systemd ユーザー権限(nobody推奨)による最小権限実行を組み合わせる。
ライセンス:本記事のテキスト/コードは特記なき限り
CC BY 4.0 です。引用の際は出典URL(本ページ)を明記してください。
利用ポリシー もご参照ください。
コメント