繋がらないという報告を四層に割る
一言でいうと
ネットワーク障害の診断の90%は、どの層で止まったのかを最初に決めることで片づきます。層を決めずにツールを起動しても、時間が過ぎるだけです。
なぜ必要なのか
「APIにつながらない」という報告を受けると、人はたいてい次のように動きます。pingを打ち、ファイアウォールのルールを開き、DNSを確認し、アプリケーションのログをあさります。順序がありません。そのため同じ場所を2回見て、見ていない場所を見ないままにします。
熟練者は違います。まず層を特定します。そして、その層に合ったツールを1つだけ使います。
どう動くのか
実務で使う層は、OSIの7階層ではなく4つあれば十分です。
| 層 | 問い | 確認ツール | 失敗したときの顔 |
|---|---|---|---|
| 名前 | この名前がどのIPに解決されるか | getent hosts, dig, resolvectl query |
Name or service not known |
| 到達 | そのIPまでパケットが届くか | ping, traceroute -U, ip route |
Network is unreachable、応答なし |
| ポート | そのIPのそのポートが開いているか | nc -zv, ss -ltn, curl --connect-timeout |
Connection refused / timed out |
| 応答 | 開いているのに応答がおかしいか | curl -v, curl -w, アプリケーションのログ |
5xx、遅い、誤った本文 |
ポイントは、層ごとに失敗の顔が異なることです。その顔を正確に読むだけで、層が決まります。
errno別の判別表を覚えておけば、報告の文面を見ただけで層が分かれます。
| メッセージ | errno | 実際に起きたこと | 最初に見る場所 |
|---|---|---|---|
Name or service not known |
EAI_NONAME | 名前解決で失敗しました。ソケットを開くこともできませんでした | nsswitch.conf、resolv.conf、/etc/hosts |
Network is unreachable |
ENETUNREACH | ルーティングテーブルに経路がありません | ip route、特にIPv6の経路 |
No route to host |
EHOSTUNREACH | ICMP unreachableを受信したか、ARPに応答がありません | 宛先の電源、ARP、REJECTルール |
Connection refused |
ECONNREFUSED | 宛先がRSTを返しました | 宛先ホストのプロセスとバインドアドレス |
Connection timed out |
ETIMEDOUT | SYNをすべて再送しても応答がありませんでした | ファイアウォールのDROP、セキュリティグループ、acceptキュー |
ここで最もよく間違えるのが、refusedをファイアウォールのせいにすることです。refusedはRSTを受け取ったという意味で、RSTを受け取ったなら、ルーティング・セキュリティグループ・NAT・ネットワークポリシーをすでにすべて通過した証拠です。実務のファイアウォールはほぼ常にDROPポリシーなので、塞がれたポートはtimeoutとして現れます。refusedを見てファイアウォールを調べるのは、すでに通過したゲートをもう一度確認することです。
時間も証拠です。Linuxのデフォルト値(net.ipv4.tcp_syn_retries=6)では、応答のない接続は1+2+4+8+16+32+64 = 127秒であきらめます。アプリケーションのタイムアウトが30秒と書かれているのに実際には127秒で失敗したなら、そのタイムアウト設定が適用されていないというサインです。
現場での姿
「ローカルでは動くのに、リモートからだけ動かない」。 十中八九、バインドアドレスの問題です。ss -ltnpで127.0.0.1:8080をリッスンしていると、Pod IPに来る接続はカーネルがRSTで拒否します。つまりrefusedです。逆にPod IPに対してもtimeoutになるなら、そこからネットワークポリシーを見ます。この1回の切り分けで、調査範囲が半分になります。
次にすること
最も下の層である名前解決から始めます。/etc/hostsとnsswitch.confがなぜdigより先なのか、そしてなぜdigはその両方をまったく見ないのかを、手で確認します。