Kubernetesの「見えない」失敗
私たちは皆,同じような経験をしています。マイクロサービスが500 Internal Server Errorを返しているのに、アプリケーションログには何も出力されていない。kubectl logsを確認しても何も表示されず、Prometheusを見てもCPU使用率は正常。それでも、サービスは明らかに壊れている。これが分散システムのデバッグの現実です。最も深刻な失敗は、アプリケーションコードと基盤となるカーネルの間の「隙間」で発生することが多いのです。
DevOpsエンジニアは、次のような3つの「ブラックボックス」シナリオによく遭遇します。
- コンテナが
exit code 137や139で即座にクラッシュし、ログ集約ツールがスタックトレースを拾う余裕がない。 - 高並列のデータベース書き込み時にのみ発生する、断続的な50ミリ秒のレイテンシスパイク。
- プロセスが読み取り専用ボリュームに書き込もうとしているが、アプリケーションがエラーメッセージを飲み込んでしまい、静かに発生している権限エラー。
なぜ従来のツールは本番環境で通用しないのか
straceやtcpdumpのような標準的なLinuxツールは、クラウドネイティブ時代を想定して作られていません。トラフィックの多い本番環境のプロセスでstraceを実行しようとすると、アプリケーションの動作が10倍から50倍も遅くなる可能性があります。このパフォーマンスへの影響により、調査中にバグが消えてしまうこともあります。これがいわゆる「ハイゼンバグ(Heisenbug)」です。さらに重要なのは、これらのツールが認識するのはプロセスID(PID)であり、Pod名やネームスペースではないということです。500ノードのクラスターで生のPIDを特定のコンテナに紐付ける作業は、手動では悪夢のような作業です。
eBPFの利点:Inspektor Gadget
Inspektor Gadgetは、eBPF(Extended Berkeley Packet Filter)を使用することでこの問題を解決します。すべてのシステムコールを傍受してカーネルとユーザー空間の間でコンテキストスイッチを行う代わりに、Linuxカーネル内で直接サンドボックス化されたプログラムを実行します。これにより、オーバーヘッドはほぼゼロ(通常は1%未満)に抑えられ、高負荷の本番環境でも安全に使用できます。
| 機能 | 従来のツール (strace/tcpdump) | Inspektor Gadget (eBPF) |
|---|---|---|
| パフォーマンスへの影響 | 深刻(アプリが停止する可能性あり) | 無視できる程度(CPU負荷1%未満) |
| K8sコンテキスト | 手動のマッピングが必要 | ネイティブ(Pod、ラベル、ネームスペースでフィルタ) |
| インストール | コンテナイメージ内に含める必要がある | ゼロ・インストルメンテーション(ノード上で動作) |
| セキュリティ | プロセスをクラッシュさせる高いリスク | カーネルのJITコンパイラにより安全性が検証済み |
開始前に考慮すべきこと
メリット: コードを一行も変更したり、Dockerイメージをビルドし直したりする必要はありません。外部から内部を覗き込むだけで動作します。
現実的な注意点: ガジェットの全機能を利用するには、Linuxカーネルのバージョンが5.10以上である必要があります。また、カーネルにフックするため、エージェントをデプロイするにはクラスターへの管理者権限(特権アクセス)が必要です。
環境の準備
私の経験上、最もスマートな管理方法はkubectlプラグイン経由で行うことです。これにより、デバッグコマンドを他のkubectl操作と同じように扱うことができます。
1. CLIのインストール
Krewをインストールしていれば、数秒でセットアップが完了します。
kubectl krew install gadget
kubectl gadget version
2. DaemonSetのデプロイ
Inspektor Gadgetは、eBPFプログラムをロードするために各ノードに「マネージャー」を必要とします。次のコマンドを実行して、必要なリソースをgadgetネームスペースにデプロイします。
kubectl gadget deploy
30秒ほど待ち、各ノードでPodがRunning状態になっていることを確認してください。
実践的なデバッグシナリオ
理論はここまでにして、実際の課題を解決してみましょう。
不正プロセスの捕捉
コンテナが侵害されたり、許可されていないスクリプトが実行されたりしていないか不安に思ったことはありませんか?trace execガジェットは、新しいプロセスが開始された瞬間にそれをキャプチャします。
kubectl gadget trace exec --namespace production --pod-label app=payment-gw
このコマンドは、実行されているコマンドをリアルタイムでストリーミング表示します。Javaバイナリのみを実行するはずのコンテナ内でcurl http://malicious-site.comや/bin/shが見つかった場合、重大なセキュリティホールを発見したことになります。
「Connection Refused」の謎を解く
Kubernetesのネットワーキングは複雑です。サービス間の接続が失敗したとき、それはDNSの問題でしょうか、NetworkPolicyによるブロックでしょうか、それともパケットドロップでしょうか?trace tcpを使用して、ハンドシェイクをリアルタイムで確認します。
kubectl gadget trace tcp --namespace my-app
送信元IP、宛先ポート、TCPの状態が表示されます。SYNは送信されているがSYN-ACKが返ってこない場合、ファイアウォールや設定ミスのあるサービスメッシュによってパケットが破棄されている可能性が高いです。
Permission Deniedエラーの特定
アプリが「File not found」と言っているのに、Podにexecで入るとファイルが存在する場合、通常は権限の不一致が原因です。trace openガジェットは、すべてのファイルアクセス試行とそのリターンコードを表示します。
kubectl gadget trace open --namespace backend --pod-label component=db
-13 (EACCES) のようなリターンコードを探してください。どのファイルパスがエラーの原因かを正確に特定できるため、手動でls -laを確認し続ける手間が省けます。
最小権限セキュリティの自動化
advise network-policyガジェットは、大幅な時間の節約になります。NetworkPolicyのYAMLを手動で書く代わりに、アプリの実際のトラフィックを記録して、ツールにポリシーを生成させることができます。
- 記録: 統合テストを実行しながら、
kubectl gadget advise network-policy monitor --namespace staging --output ./traffic.jsonを10分間実行します。 - 生成:
kubectl gadget advise network-policy report --input ./traffic.jsonを実行します。
これにより、アプリが実際に必要とする特定のトラフィックのみを許可する、本番環境対応のKubernetes NetworkPolicyが出力されます。
本番環境で安全に運用するために
eBPFは効率的ですが、これらのトレーサーを永久に実行し続けるべきではありません。以下のガードレールを推奨します。
- 積極的にフィルタリングする: クラスター全体で広範囲なトレースを実行しないでください。データ量を管理可能な範囲に抑えるため、常に
--namespaceや--pod-labelを使用してください。 - ターゲットを絞ったセッション: ガジェットを外科医のメスのように使ってください。バグを特定するためにオンにし、特定できたらオフにします。長期的なモニタリングには、標準的なメトリクスを使用してください。
- RBACによる制御:
kubectl gadgetは機密性の高いシステムデータへの深い可視性を提供するため、許可されたSREのみが実行できるように制限してください。
まとめ
Inspektor Gadgetは、Kubernetesという「ブラックボックス」を透明な環境に変えてくれます。低レベルのカーネルイベントを抽出し、それを高レベルのKubernetesの概念にマッピングすることで、デバッグから推測を排除します。失敗したTCPハンドシェイクのトラブルシューティングであれ、ファイルアクセスの監査であれ、eBPFは本番環境をクラッシュさせることなく、真実を教えてくれます。

