トリアージの順序と記録
一言でいうと
障害対応で実力の差が出るのは、ツールではなく順序と記録です。順序があれば同じ場所を二度見ることがなく、記録があれば次の人が最初からやり直さずに済みます。
なぜ必要なのか
午前3時に届いた通報を受ければ、誰でも焦ります。焦ると順序が崩れ、順序が崩れると「さっき確認したっけ?」という問いが繰り返されます。そのため熟練者は、あらかじめ決めておいた順序に機械的に従います。判断は、データを集めてから行います。
どう動くのか
順序は下から上へ上がっていきます。下の層が壊れていれば、上の層を見る必要がないからです。
- 名前 —
getent hosts <name>とdig +short <name>を並べて実行します。2つの結果が違えば、その違いこそが原因の場所です。 - 到達 —
ping -c 3 <IP>。失敗しても、すぐに結論を出しません。ICMPが遮断されているだけかもしれません。 - ポート —
nc -zv -w 2 <IP> <port>。refusedなのかtimeoutなのかを、必ず区別して書きます。この一語が、次の調査の方向を決めます。 - バインド — 対象ホストで
ss -ltnp | grep <port>。Local Addressが127.0.0.1なら、そこで答えが出ます。 - 応答 —
curl -o /dev/null -s -w '...'。ステータスコードと区間ごとの時間を一緒に見ます。
各ステップで、コマンドとその出力をそのまま残します。「確認済み」とだけ書かれた記録は、次の人にとって何の価値もありません。逆に、コマンドと出力が添えられていれば、次の人はその出力を読み直して、別の結論を出すこともできます。
ポストモーテム報告書には、少なくとも次の5つが必要です。
| 項目 | 内容 |
|---|---|
| 症状 | ユーザーが実際に見たもの(推測ではない) |
| 層 | どの層で止まったか |
| 原因 | 根拠となるコマンドの出力と一緒に |
| 対処 | 何をどう変えたか |
| 再発防止 | 同じことが二度と起きないようにするには |
層ごとに何を叩くか
「動かない」を絞り込む順序があります。下から上へ上がっていけば、1段ごとに候補が減ります。
| 層 | 確認コマンド | ここで失敗したら |
|---|---|---|
| 1. 名前 | getent hosts api.example.com |
DNS・/etc/hosts・検索ドメイン |
| 2. 経路 | ip route get 10.0.3.12 |
ルーティング・デフォルトゲートウェイ |
| 3. 到達 | ping -c1 10.0.3.12 |
ICMPが塞がれているだけかもしれない(失敗しても次へ) |
| 4. ポート | nc -zv 10.0.3.12 8080またはcurl -v telnet://… |
ファイアウォール・セキュリティグループ・リッスンしていない |
| 5. サービス | curl -sv http://10.0.3.12:8080/healthz |
アプリケーション |
3番で失敗しても止まらないことが重要です。ICMPはよく塞がれているので、「pingが通らないからネットワークの問題」はしばしば外れます。4番が本当の判定です。
ncの結果は3つに分かれ、それぞれ意味が違います。
- connected — ポートが開いています。問題は5番より上にあります。
- Connection refused — パケットは届いていて、誰もリッスンしていません。サービスが起動していないか、別のポートにバインドしています。ファイアウォールの問題ではありません。
- timeout — パケットが消えました。ファイアウォール・セキュリティグループ・ルーティングの側です。
この3つを区別するだけで、調査範囲が大きく変わります。
どこでリッスンしているかを確かめる
Connection refusedが出たら、サーバー側で見ます。
ss -ltnp | grep 8080
LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:(("app",pid=42,fd=3))
↑ the trap is here
127.0.0.1:8080なら、自分自身からしか届きません。コンテナの中でcurl localhost:8080は通るのに、外からは通らない典型的な原因です。外から接続するには、0.0.0.0:8080か[::]:8080である必要があります。
アプリケーションの設定で、バインドアドレスを直します(--host 0.0.0.0、bind = "0.0.0.0")。これが間違っていれば、ポートマッピングをいくら直しても通りません。
Kubernetesではもう1層
Pod同士が通信できないときは、まずネットワークポリシーを疑います。デフォルト拒否(default deny)がかかったネームスペースでは、ポリシーに書かれていない通信はすべてtimeoutになります。
kubectl -n <ns> get networkpolicy
kubectl -n <ns> describe networkpolicy <name> # read from/to
症状が「ときどき通る」なら、ポリシーではなくエンドポイントを見ます。3つのPodのうち1つだけがReadyでなければ、その1つに行ったリクエストだけが失敗し、外からは断続的なエラーに見えます。
kubectl -n <ns> get endpoints <svc> # how many addresses are there?
現場での姿
原因が1つだと仮定すること。 実際の障害は、2つ以上の原因が重なっていることが多いです。1つを直して「直らない」と別の方向へ行くと、すでに直したものまで疑うことになります。そのため、各層を最後まで確認し、見つけたものをすべて書き留めておくほうが、結局は早く済みます。
直したあとに検証しないこと。 hostsを直したらgetentでもう一度確認し、バインドを直したら外側のアドレスでもう一度叩く必要があります。同じコマンドで失敗を再現し、成功を確認することが、対処の最後の段階です。
次のラボですること
3つの欠陥が同時に起きている障害を受け取ります。層を1つずつ絞り込んで原因を特定し、直し、決まった形式でポストモーテム報告書を残します。