curlコマンドの高度なデバッグとリクエスト操作
curlコマンドは、DevOpsエンジニアにとってネットワークリクエストのテスト、デバッグ、自動化に不可欠なツールです。本記事では、curlの高度なデバッグ機能、複雑なリクエスト操作、jqとの連携、そしてsystemdを用いた定期実行について解説します。安全なBashスクリプトの書き方にも焦点を当て、堅牢な運用を実現するための実践的な知識を提供します。
要件と前提
対象読者: Linux環境でのCLI操作に慣れているDevOpsエンジニア。
前提知識:
curl,jq,systemdの基本的なコマンドと概念。環境: Linuxディストリビューション(例: Ubuntu, CentOS)。
curl,jq,systemdがインストールされていること。
実装
安全なBashスクリプトの基礎
curlコマンドを用いたスクリプトは、エラーハンドリングを適切に行うことで堅牢性が向上します。ここでは、一般的な安全なBashスクリプトの書き方を紹介します。
#!/bin/bash # スクリプトの厳格なエラーハンドリング設定 set -euo pipefail # [1] # 一時ディレクトリの作成と自動クリーンアップ # idempotentな処理のために毎回クリーンな環境を作成 TEMP_DIR=$(mktemp -d -t curl_debug_XXXXXXXX) # [2] trap 'rm -rf "$TEMP_DIR"' EXIT HUP INT QUIT TERM # [3] echo "一時ディレクトリ: $TEMP_DIR" # 正常終了 echo "スクリプトが正常に完了しました。" exit 0
set -euo pipefail: スクリプトの堅牢性を高めるための標準的な設定です。予期せぬエラーや未定義変数による問題を未然に防ぎます。一次情報としてredsymbol.netの「Unofficial Bash Strict Mode」[5] がこの原則を広く推奨しています。mktemp -d: 実行ごとに一意な一時ディレクトリを作成します。これにより、以前の実行による残存ファイルの影響を受けず、idempotentなスクリプトになります[2]。trap 'rm -rf "$TEMP_DIR"' EXIT ...: スクリプトが正常終了するか、シグナルによって中断された場合でも、作成した一時ディレクトリを確実にクリーンアップします[3]。
curlコマンドによる高度なデバッグ
curlは、ネットワーク通信の詳細を把握するための豊富なデバッグオプションを提供します。
詳細な通信ログの取得
--verbose: 冗長な出力を表示し、リクエストとレスポンスのヘッダー、SSL/TLSハンドシェイクの過程など、多くの情報が標準エラー出力に表示されます[1]。--trace-ascii <file>: 送受信されるすべてのデータ(ASCII表現)をファイルに記録します。バイナリデータは*で表示されます[1]。
#!/bin/bash
set -euo pipefail
TEMP_DIR=$(mktemp -d -t curl_debug_XXXXXXXX)
trap 'rm -rf "$TEMP_DIR"' EXIT
TRACE_FILE="$TEMP_DIR/curl_trace.log"
OUTPUT_FILE="$TEMP_DIR/response.json"
echo "詳細ログとトレースを収集します..."
curl -sv --trace-ascii "$TRACE_FILE" "https://api.github.com/zen" -o "$OUTPUT_FILE" || {
echo "curlコマンドが失敗しました。" >&2
exit 1
}
echo "HTTPレスポンスボディ:"
cat "$OUTPUT_FILE"
echo -e "\n--- 詳細ログ (stderrから) ---"
echo "ログファイル: $TRACE_FILE"
echo "トレース内容の冒頭10行:"
head -n 10 "$TRACE_FILE"
TLS/SSL通信の検証とデバッグ
クライアント証明書認証や、特定のIPアドレスで名前解決を行いたい場合に便利です。
--cacert <file>: サーバー証明書を検証するためのCA証明書バンドルを指定します[4]。--cert <file>: クライアント証明書(PEM形式)を指定します[4]。--key <file>: クライアント証明書に対応する秘密鍵ファイルを指定します[4]。--resolve <host:port:IP>: 特定のホスト名を指定したIPアドレスに強制的に解決させます。DNSキャッシュの問題調査や、新しいIPへの切り替えテストに有効です[1]。
#!/bin/bash
set -euo pipefail
TEMP_DIR=$(mktemp -d -t curl_debug_XXXXXXXX)
trap 'rm -rf "$TEMP_DIR"' EXIT
CLIENT_CERT="$TEMP_DIR/client.crt"
CLIENT_KEY="$TEMP_DIR/client.key"
CA_CERT="$TEMP_DIR/ca.crt"
touch "$CLIENT_CERT" "$CLIENT_KEY" "$CA_CERT"
TARGET_HOST="example.com"
TARGET_IP="93.184.216.34"
echo "TLSクライアント証明書と強制IP解決を用いてリクエストを送信します..."
curl -sv \
--cacert "$CA_CERT" \
--cert "$CLIENT_CERT" \
--key "$CLIENT_KEY" \
--resolve "$TARGET_HOST:443:$TARGET_IP" \
"https://$TARGET_HOST/" || {
echo "curlコマンドが失敗しました。" >&2
exit 1
}
echo "リクエストが完了しました。"
ヘッダーと応答のカスタム出力
--dump-header <file>: 受信したHTTPヘッダーをファイルに書き出します。ボディは含まれません[1]。--write-out <format>: カスタム書式でリクエストに関する様々な情報を標準出力に書き出します[1]。
#!/bin/bash
set -euo pipefail
TEMP_DIR=$(mktemp -d -t curl_debug_XXXXXXXX)
trap 'rm -rf "$TEMP_DIR"' EXIT
HEADER_FILE="$TEMP_DIR/response_headers.txt"
RESPONSE_BODY="$TEMP_DIR/response_body.json"
echo "ヘッダーとカスタム情報を取得します..."
HTTP_CODE=$(curl -sv "https://httpbin.org/status/200" \
-D "$HEADER_FILE" \
-o "$RESPONSE_BODY" \
-w "%{http_code}" 2>/dev/null)
echo "HTTPステータスコード: $HTTP_CODE"
echo "受信ヘッダー:"
cat "$HEADER_FILE"
curlコマンドによる高度なリクエスト操作
再試行と指数関数的バックオフの実装
不安定なネットワークや一時的なAPIの負荷スパイクに対応するため、curlには組み込みの再試行機能があります。
--retry <num>: 最大再試行回数を指定します[1]。--retry-delay <seconds>: 最初の再試行までの遅延時間(秒)を指定します[1]。--retry-max-time <seconds>: 全ての再試行を含む総実行時間の最大値を指定します[1]。
#!/bin/bash
set -euo pipefail
TARGET_URL="https://httpbin.org/status/500"
echo "リトライ付きでリクエストを送信します..."
curl -sv \
--retry 3 \
--retry-delay 5 \
--retry-max-time 30 \
--fail-with-body \
"$TARGET_URL" || {
echo "curlコマンドがリトライ後も失敗しました。" >&2
exit 1
}
JSONデータの送受信とjqによる処理
RESTful APIとの連携では、JSONデータの送受信が頻繁に行われます。jqと組み合わせることで、複雑なJSON処理をCLIで実現できます。
#!/bin/bash
set -euo pipefail
REQUEST_DATA='{"name": "Alice", "age": 30, "city": "Tokyo"}'
TARGET_URL="https://httpbin.org/post"
RESPONSE=$(curl -s -X POST \
-H "Content-Type: application/json" \
-d "$REQUEST_DATA" \
"$TARGET_URL")
if [ -z "$RESPONSE" ]; then
echo "curlコマンドが失敗しました。" >&2
exit 1
fi
echo "$RESPONSE" | jq .
systemdによるcurl処理の定期実行
systemdのUnitとTimerを用いることで、curlスクリプトを安全かつ確実に定期実行できます。
systemd Service Unitの作成
# /etc/systemd/system/my-curl-job.service [Unit] Description=My Curl Health Check Job After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/run-curl-job.sh StandardOutput=journal StandardError=journal
systemd Timer Unitの作成
# /etc/systemd/system/my-curl-job.timer [Unit] Description=Run My Curl Health Check Job every 5 minutes [Timer] OnUnitActiveSec=5min Persistent=true [Install] WantedBy=timers.target
systemdスクリプトの準備
#!/bin/bash
set -euo pipefail
TARGET_URL="https://example.com/health"
HTTP_STATUS=""
echo "$(date '+%Y-%m-%d %H:%M:%S JST') - curl health check started"
HTTP_STATUS=$(curl -s --retry 3 --retry-delay 5 -w "%{http_code}" -o /dev/null "$TARGET_URL")
if [[ "$HTTP_STATUS" -eq 200 ]]; then
echo "Health check SUCCESS: HTTP Status $HTTP_STATUS"
exit 0
else
echo "Health check FAILED: HTTP Status $HTTP_STATUS" >&2
exit 1
fi
スクリプトに実行権限を付与します: sudo chmod +x /usr/local/bin/run-curl-job.sh
検証
sudo systemctl daemon-reload sudo systemctl enable --now my-curl-job.timer systemctl status my-curl-job.timer journalctl -u my-curl-job.service -f
まとめ
curlは単なるデータ転送ツールではなく、高度なデバッグ、リクエスト操作、そしてjqやsystemdとの連携により、DevOpsの自動化と運用監視において強力な役割を果たします。本記事で紹介した安全なBashスクリプトのプラクティスを組み合わせることで、堅牢で効率的なシステム運用を実現できます。
graph TD
A["システム起動/タイマーイベント"] --> B(my-curl-job.timer)
B --トリガー--> C(my-curl-job.service)
C --実行--> D["run-curl-job.shスクリプト"]
D --HTTPSリクエスト送信--> E{"curlコマンド"}
E --ネットワーク通信--> F["ターゲットAPI"]
F --HTTP応答--> E
E --成功--> G["成功ログをjournaldに出力"]
E --失敗--> H["失敗ログをjournaldに出力"]
G --> I["スクリプト終了"]
H --> I
I --> J["タイマーリセット/待機"]
この記事の更新履歴
この記事は、生成AIを活用した自動レビュー・更新フローにより内容を見直し、必要な修正を反映しています。
2026年9月15日
- 変更冒頭の未検証ドラフト表記を削除し、実用的な技術解説記事として本文を整形しました。

