TT Lab
はじめる
学ぶ 学習パス コース

CCA — Cilium認定アソシエイト

フローはどこにどれだけ残っているのか

TT Labで続きを見る

一言でいうと

Hubbleは、eBPFデータパスが生成したイベントをノードローカルのリングバッファに溜め、relayがそれをクラスター単位でまとめます。リングバッファはローテーションするため、長期の分析にはexportが必須です。

なぜ必要なのか

ポリシーを強制適用し始めると、疑問が噴き出します。「さっき決済APIがなぜ切れたのか」「このドロップはポリシーのせいか、ルーティングのせいか」。データパスがカーネルの中に入った以上、観測手段も同じ深さから取り出す必要があります。

従来の方式は、サイドカープロキシを付けてリクエストを観測していました。Podごとにプロキシが1つずつ付くのでリソースが2倍になり、Podスペックを変える必要があるので再起動も必要です。Hubbleは、すでにデータパスに付いているeBPFプログラムが生成したイベントをそのまま読み取るので、追加のプロキシもPodの変更も必要ありません。

どう動くのか

構造は3層です。

[eBPF 데이터패스] --perf 링버퍼--> [cilium-agent 안의 Hubble 서버]
                                      gRPC :4244
                                          |
                                   [hubble-relay] :4245
                                          |
                            +-------------+-------------+
                            v                           v
                      [hubble CLI]                [hubble-ui]

ここから、運用上重要な性質が3つ出てきます。

1つ目は、フローがノードローカルのメモリにしか一時的に存在しないことです。デフォルトのバッファはノードあたり4095フローで、拡張しても、よく使われる値は16383です。フロー1つが約500バイトを占めるので、16383ならノードあたりおよそ8MiBです。トラフィックの多いノードでは数秒でローテーションすることがあるので、監査の証跡や事後分析には、必ずファイルへのexportを付ける必要があります。

2つ目は、relayは集約役にすぎず、保存先ではないことです。relayが落ちても、データパスとノードローカルの観測はまったく影響を受けません。ポートは、relayが4245、ノードのHubbleサーバーが4244、メトリクスエンドポイントが9965です。

3つ目は、ペイロードは保存しないことです。フローは、送信元・宛先のアイデンティティとラベル、判定(verdict)、ドロップの理由、HTTP/DNSのメタデータを含む構造化イベントです。パケットの内容が必要なら、別のツールを使う必要があります。

判定値の読み方が、実戦の核心です。

verdict 意味
FORWARDED 許可されて転送された
DROPPED ブロックされた(ドロップの理由が一緒に付く)
AUDIT 監査モードだったが、強制状態であればブロックされたトラフィック
ERROR 処理中のエラー

ドロップの理由ごとに、最初に疑う箇所を整理しておくと時間を節約できます。POLICY_DENIEDはポリシーで許可されていないのでアイデンティティとポートを見直し、CT_MAP_INSERT_FAILEDはconntrackマップが満杯なのでマップのサイズを調整し、UNSUPPORTED_L3_PROTOCOLはIP以外のトラフィックであり、STALE_OR_UNROUTABLE_IPはipcacheの不一致なので、ノード間の同期を点検します。

最後に、必ず区別しておくべきことがあります。L7の拒否は、L4のドロップとログの形が異なります。 L4で止められると接続が成立せず、リクエスト1行で終わりますが、L7ルール違反は、すでに確立された接続の上でプロキシが403を作って返すので、リクエストはDROPPED、応答はFORWARDEDと記録されます。この非対称を知っていれば、ログ2行を見るだけで、どの層の問題なのかを判定できます。

現場での姿

筆者がホームラボにHubbleを導入したとき、hubble-relayとhubble-uiがPendingのまま動きませんでした。イベントは次のとおりです。

Warning  FailedScheduling  0/1 nodes are available: 1 node(s) had untolerated taint(s).

原因はスケジューリングでした。コントロールプレーンノードにはnode-role.kubernetes.io/control-plane:NoScheduleのtaintがかかっていますが、hubble-relayとhubble-uiはDaemonSetではなくDeploymentなので、tolerationがありませんでした。CoreDNSは、デフォルトでcontrol-planeのtolerationを持っているため、正常に起動できたのと対照的です。ワーカーノードが参加するとすぐに解消され、これはエラーではなく、正常な動作でした。

ここで身に付けたい感覚があります。Cilium AgentとHubbleサーバーは、ノードごとに必要なのでDaemonSetであり、relayとUIは、クラスターに1つあれば足りるのでDeploymentです。デプロイの形が違えば、スケジューリングの制約も違います。「agentはすべて起動したのに、hubble CLIだけが接続できない」場合は、relay Podの状態から見るのが順番です。

同じクラスターでL7ポリシーをかけて得たログは、前のモジュールで見たとおりです。GETリクエストはFORWARDED、POSTリクエストはDROPPED、そしてそのPOSTに対する403応答はFORWARDED。ログ3行が、ポリシーが意図どおりに動作したことの証拠でした。

次のラボですること

Hubbleを有効にする値と、メトリクス・exportの設定を作成し、実際のワークロードにラベルを付けて、アイデンティティに含まれるラベルと除外されるラベルをConfigMapで整理し、よく使うフローフィルターのクエリとドロップ理由の診断表、そしてドロップ急増のアラートルールまで作ります。