netstat/ssコマンドによるネットワーク診断

Tech

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

netstat/ssコマンドによるネットワーク診断

DevOpsエンジニアとして、アプリケーションのパフォーマンス問題や接続障害が発生した際、迅速なネットワーク診断は不可欠です。本稿では、Linuxにおけるnetstatおよびssコマンドを用いた診断手法を、安全なBashスクリプト、jqcurl、そしてsystemdによる自動化と組み合わせて解説します。

要件と前提

要件

  • netstat/ssコマンドによるネットワーク接続状態の確認とトラブルシューティング。

  • bashスクリプトはset -euo pipefailtrap、安全な一時ディレクトリ (mktemp -d) を用いたidempotentかつ安全な書き方を遵守。

  • jqによるJSON処理、curlによるTLS/再試行/バックオフの例示。

  • systemd unit/timerによる診断の自動化。

  • mermaidフローチャートによる診断プロセスの可視化。

  • root権限の扱いと権限分離への言及。

前提

  • Linux環境(Ubuntu/CentOSなど)が利用可能であること。

  • bashss(iproute2パッケージに含まれる)、jqcurlsystemdがインストール済みであること。

実装

ネットワーク診断スクリプト (diagnose_network.sh)

以下のスクリプトは、ssコマンドでネットワーク接続情報を取得し、curlで特定のAPIエンドポイントへの疎通確認を行います。取得したJSONデータはjqで処理されます。

#!/usr/bin/env bash

set -euo pipefail

# 安全な一時ディレクトリの作成と自動クリーンアップ

readonly TMPDIR=$(mktemp -d -t network-diag-XXXXXX)
function cleanup {
    echo "--- INFO: Cleaning up temporary directory ${TMPDIR} ---"
    rm -rf "${TMPDIR}"
}
trap cleanup EXIT # スクリプト終了時にcleanup関数を実行

echo "--- $(date '+%Y-%m-%d %H:%M:%S') --- ネットワーク接続診断開始 ---"

# 1. ssコマンドによるネットワーク接続状態の確認


# -t: TCPソケット, -u: UDPソケット, -n: ホスト名/ポート番号を解決しない, -a: 全てのソケットを表示, -p: プロセス情報を表示


# 注意: '-p' オプションは、通常root権限(またはCAP_NET_ADMIN)が必要です。


# 一般ユーザーで実行する場合は、'-p' を外すか、sudoersで適切な権限を付与してください。

echo "### TCP/UDPのLISTENおよびESTABLISHED状態の接続を表示 (プロセス情報付き、要root権限の場合あり) ###"
if ss -tunap > "${TMPDIR}/ss_output.txt" 2>&1; then
    cat "${TMPDIR}/ss_output.txt"
    echo
    echo "--- 特定ポート(例: 22 SSH)の接続状況 ---"
    if grep -E ':(22|ssh)' "${TMPDIR}/ss_output.txt" | head -n 1 >/dev/null; then
        grep -E ':(22|ssh)' "${TMPDIR}/ss_output.txt"
    else
        echo "ポート 22 (SSH) の接続は見つかりませんでした。"
    fi
else
    echo "ERROR: ssコマンドの実行に失敗しました。権限やインストール状況を確認してください。" >&2
    cat "${TMPDIR}/ss_output.txt" >&2 # ssのエラー出力を表示
    exit 1
fi
echo

# 2. curlコマンドによるAPI疎通確認 (TLS/再試行/バックオフ)

readonly API_ENDPOINT="https://jsonplaceholder.typicode.com/todos/1" # テスト用公開API
readonly MAX_RETRIES=3
readonly RETRY_DELAY=5 # 秒
readonly TOTAL_RETRY_TIME=$((MAX_RETRIES * RETRY_DELAY * 2)) # 最大リトライ時間

echo "### API疎通確認: ${API_ENDPOINT} (最大${MAX_RETRIES}回リトライ) ###"
if curl -sS --fail-with-body \
        --retry "${MAX_RETRIES}" \
        --retry-delay "${RETRY_DELAY}" \
        --retry-max-time "${TOTAL_RETRY_TIME}" \
        --output "${TMPDIR}/api_response.json" \
        "${API_ENDPOINT}"; then
    echo "API接続成功。"

    # 3. jqによるJSONデータの処理

    echo "--- 取得したJSONデータの一部をjqで処理 ---"
    if jq '.title' "${TMPDIR}/api_response.json" > /dev/stdout; then
        echo "JSON処理成功。"
    else
        echo "ERROR: jqによるJSON処理に失敗しました。" >&2
        cat "${TMPDIR}/api_response.json" >&2 # 取得したJSONを表示
        exit 1
    fi
else
    echo "ERROR: API接続に失敗しました: ${API_ENDPOINT}" >&2
    if [[ -f "${TMPDIR}/api_response.json" ]]; then
        echo "--- エラーレスポンス ---" >&2
        cat "${TMPDIR}/api_response.json" >&2
    fi
    exit 1
fi

echo "--- ネットワーク接続診断完了 ---"
exit 0

root権限の扱いと権限分離

  • ss -pオプション: プロセスID (PID) やプロセス名を詳細に表示するには、通常root権限が必要です。一般ユーザーで実行すると情報が制限されるか、エラーになる場合があります。

  • 最小権限の原則: 診断スクリプトは、必要な情報に応じてsudoを使用するか、CAP_NET_ADMINなどのLinux Capabilitiesをプロセスに付与することを検討してください。

  • systemdUser/Group: 後述のsystemdユニットではUser=およびGroup=オプションで実行ユーザーを指定し、不必要なroot権限での実行を避けることができます。この場合、ss -pのような特権操作はできません。

検証

上記スクリプトをdiagnose_network.shとして保存し、実行権限を与えます。

chmod +x diagnose_network.sh

# root権限が必要なss -pを含む場合

sudo ./diagnose_network.sh

# 一般ユーザーで実行する場合 (ss -pの情報は制限されるか表示されない)

./diagnose_network.sh
  • ssコマンドの出力: LISTEN、ESTABLISHED、TIME_WAITなどの状態や、ローカル/リモートのアドレス・ポート、およびプロセス情報(root権限時)が正しく表示されることを確認します。

  • curlの出力: API接続が成功し、HTTPステータスコード200が返されること、およびリトライメカニズムが機能すること(ネットワーク一時障害を模擬するなど)を確認します。

  • jqの出力: 取得したJSONデータから.titleフィールドが正しく抽出されることを確認します。

運用

systemdによる自動化

診断スクリプトを定期的に実行し、ログを収集するためにsystemdservicetimerユニットを定義します。

1. スクリプトの配置

スクリプトを/usr/local/bin/diagnose_network.shに配置します。 (ここではss -pは一般ユーザーでは機能しないことを前提に、権限分離を優先しUser=someuserを設定します。必要であればスクリプトから-pオプションを削除してください。)

sudo install -m 755 diagnose_network.sh /usr/local/bin/

2. systemd serviceユニットの作成 (/etc/systemd/system/network-diag.service)

[Unit]
Description=Automated Network Connection Diagnostic
Documentation=https://example.com/network-diag-service
After=network.target

[Service]
Type=oneshot

# 診断スクリプトを特定の一般ユーザー/グループで実行


# 必要に応じて、専用ユーザー (例: networkdiag) を作成し、ここに指定

User=nobody
Group=nogroup
ExecStart=/usr/local/bin/diagnose_network.sh

# StandardOutput, StandardError はデフォルトでjournaldに送られる

StandardOutput=journal
StandardError=journal

# 失敗時にアラートなど、後続の処理を追加可能 (例: OnFailure=alert-script.service)

[Install]
WantedBy=multi-user.target

3. systemd timerユニットの作成 (/etc/systemd/system/network-diag.timer)

[Unit]
Description=Run network connection diagnostic every 5 minutes

[Timer]

# システム起動後1分後に最初の実行

OnBootSec=1min

# サービスがアクティブになった5分後に再度実行 (定期的実行)

OnUnitActiveSec=5min

# 同時実行を避けるためのランダムな遅延

RandomSec=30s

[Install]
WantedBy=timers.target

4. systemdユニットの有効化と起動

sudo systemctl daemon-reload
sudo systemctl enable --now network-diag.timer

5. ログの確認

systemctl status network-diag.timer
systemctl status network-diag.service
journalctl -u network-diag.service --no-pager

トラブルシュート

問題点 診断方法
接続が見えない ss -tunap: プロセスが表示されない場合、サービスが停止しているか、異なるユーザーで実行されている可能性がある。 -lでLISTENポートも確認。
ファイアウォール: sudo iptables -Lsudo ufw statusでブロックされていないか確認。
ルーティング: ip rでルーティングテーブルを確認。
TIME_WAITが多い サーバー側で大量のCLOSE_WAIT接続がある場合、アプリケーションがソケットを適切に閉じずに放置している可能性がある。クライアント側でTIME_WAITが多いのは正常な挙動。
CLOSE_WAITが多い サーバー側でアプリケーションがソケットのクローズを処理していない可能性。アプリケーションログを確認し、リソースリークやデッドロックを疑う。
curlが失敗する HTTPステータスコード: --fail-with-bodyでエラーレスポンスを確認。HTTP 4xx/5xxはアプリケーション側の問題、ネットワークの問題はcurlのエラーコードで。
curlエラーコード: man curl-errorsで詳細を確認。例:6 (Couldn’t resolve host), 7 (Couldn’t connect to host), 35 (SSL connect error)。
TLS/SSL: --verbose (-v) オプションで詳細なTLSハンドシェイクのログを確認。証明書の問題 (--cacert, --insecure) も考慮する。
systemdが動かない systemctl status <unit>: サービスの状態とエラーメッセージを確認。
journalctl -u <unit>: サービスの詳細なログを確認。
スクリプトの実行権限: ExecStartで指定されたスクリプトに実行権限があるか確認 (chmod +x)。
User/Group: 指定したユーザーが存在し、スクリプト実行に必要な権限を持っているか確認。

ネットワーク診断フロー

graph TD
    A["システム/アプリ異常検知"] --> B{"定期監視 (systemd Timer) 発火?"};
    B --|はい| C["診断Service実行"];
    B --|いいえ| D["手動診断開始"];

    C --> E["診断スクリプト実行"];
    D --> E;

    E --> F["ssコマンド実行"];
    F --> G["curlコマンド実行"];
    G --> H["jqで結果解析"];

    H --|エラー検出?| I{"はい"};
    H --|エラー検出?| J{"いいえ"};

    I --> K["診断結果ログ出力"];
    K --> L["アラート発報"];
    L --> M["担当者による詳細調査"];

    J --> K;
    K --> N["次サイクル待機"];

    M --> O["問題解決/サービス復旧"];
    O --> N;

まとめ

netstatとその後継であるssコマンドは、Linuxシステムにおけるネットワーク診断の基礎ツールです。特にssは高速かつ詳細な情報を提供します。本稿では、これらのコマンドを核に、安全なBashスクリプトの書き方、jqによるデータ解析、curlによる外部サービス疎通確認、そしてsystemdを用いた自動監視の仕組みをDevOpsエンジニアの視点から解説しました。これらの技術を組み合わせることで、システムのネットワーク状態を常に把握し、問題発生時の迅速なトラブルシューティングと安定したサービス運用に貢献できます。権限分離と最小権限の原則を忘れずに、セキュアな運用を心がけましょう。

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

コメント

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