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

CCA — Cilium認定アソシエイト

パケットはどこで掴まれ、どこへ弾かれるのか

TT Labで続きを見る

一言でいうと

Ciliumは、Kubernetesの意味論(Service、ラベル、ポリシー)をカーネル内のデータ構造へ直接下ろし込みます。そのため、Serviceが増えてもルックアップのコストは増えませんが、すべてが速くなるわけではありません。

なぜ必要なのか

kube-proxyのiptablesモードでは、Serviceへのリクエスト1つが、KUBE-SERVICESチェーンを走査し、KUBE-SVC-*チェーンで確率分岐を経て、KUBE-SEP-*チェーンでDNATされます。ルールの数はServiceの数とバックエンドの数に比例して増え、カーネルはパケットのたびにそのリストをほぼ順番に通り抜けます。

さらにつらいのは更新のコストです。iptablesは、ルールを1つ変えるときも事実上テーブル全体を書き直します。 デプロイが頻繁なクラスターでは、これがCPUのスパイクとルール反映の遅延として現れます。Serviceが数千あるような環境で「Podは起動したのに、まだトラフィックが来ない」という数秒の空白が生じるのは、ここが原因です。

eBPFは、この2つの軸をどちらも定数時間に変えます。ルックアップはハッシュマップの参照なのでServiceの数と無関係ですし、更新はマップのエントリ単位の増分なので、ほかのエントリには触れません。

どう動くのか

外部からNodePortで入ってきたパケットの道のりです。

NIC 수신
  -> [XDP 훅]            드라이버 수준. sk_buff 할당 전이라 가장 빠름
  -> [tc ingress 훅]     서비스 변환(lb4_services -> lb4_backends), conntrack,
                         ipcache 룩업으로 목적지 아이덴티티 확인
  -> bpf_redirect_peer   호스트 veth 에서 파드 네임스페이스 안 피어로 직행
  -> [파드 lxc 인터페이스] 정책 평가: (소스 아이덴티티, 포트, 프로토콜, 방향)
  -> 애플리케이션 소켓

NodePortで入ってきたパケットが通るeBPFフック。NIC受信、XDPフック、tc ingressフック、bpf_redirect_peer、Podのlxcインターフェース、アプリケーションソケットの順です。Serviceの変換とconntrackとポリシー評価はtcフックで行われ、L7ポリシーがかかったトラフィックだけがカーネルを出てユーザースペースのEnvoyを経由するため、レイテンシが加わります

押さえるべき点は3つあります。1つ目に、XDPはメモリ割り当ての前の段階なので、DDoSのフィルタリングやNodePortの高速化に使われますが、対応するNICドライバーが必要です。2つ目に、データパスの本体はtcフックで、Serviceの変換・conntrack・ポリシー評価がすべてここで行われます。3つ目に、bpf_redirect_peerは、vethペアを通過するときに発生するソフトIRQの再スケジューリング1サイクルを飛ばして、ネームスペースの境界を一度に越えます。

ポリシーはIPではなくアイデンティティで評価されます。Podのラベルの集合に数字が1つ対応し、その数字がカーネルマップのキーになります。試験にそのまま出る予約アイデンティティは、覚えておいたほうがよいでしょう。

番号 名前 意味
0 unknown 不明な送信元
1 host ローカルノード自身
2 world クラスター外部のすべて
3 unmanaged Ciliumが管理していないエンドポイント
4 health ヘルスチェックのエンドポイント
5 init 初期化中のエンドポイント
6 remote-node ほかのノード
7 kube-apiserver APIサーバー
8 ingress Ingress

役割分担も整理しておきます。Cilium AgentはDaemonSetとしてノードごとに起動し、eBPFプログラムのロード、エンドポイントの管理、ポリシーの適用、conntrackを担当します。Cilium Operatorはクラスターに1つ起動し、クラスター範囲のIPAM、CRDのガベージコレクション、ノードディスカバリーを担当します。Agentはノードのデータパスを直接操作するのでDaemonSetである必要があり、Operatorはクラスター全体の状態を扱うので1つで足ります。

最後に、正直な代償も挙げておきます。eBPFに切り替えればすべてが速くなるという話は、事実ではありません。

「どの機能を有効にすると、どんなコストがかかるのか」を知っていることが、運用の核心です。

現場での姿

筆者は、7ノードのホームラボ(cp-1/2/3 + gpu-a/b/c/d)を、Kubernetes v1.34.10、containerd 1.7.27、カーネル6.14、Cilium 1.20.1で運用しています。このクラスターはkubeadm init --skip-phases=addon/kube-proxyで、kube-proxyを最初からインストールせずに構築しました。インストール後に削除するのとは違います。一度でも動いたkube-proxyは、ノードにKUBE-SERVICES / KUBE-SVC-* / KUBE-SEP-*チェーンを刻み込み、DaemonSetを削除してもそのルールが残って、eBPFデータパスと衝突します。

主張ではなく、計測で確認した結果です。

kube-proxy 파드 수: 0
노드의 iptables KUBE- 체인 개수: 0

そして、Serviceはカーネルマップの中に次のように入っていました。

SERVICE ADDRESS             BACKEND ADDRESS (REVNAT_ID) (SLOT)
10.96.0.10:53/TCP (1)       10.244.0.150:53/TCP (4) (1)
10.96.0.1:443/TCP (1)       10.0.0.120:6443/TCP (1) (1)

cilium statusはKubeProxyReplacement: TrueとModules Health: OK 92 / Degraded 0を報告し、ノードの状態・コントロールプレーン・CNI・CoreDNS・スケジューリング・Service DNSを含む基本検証の14項目が14/14で合格しました。これらの数字が重要な理由は単純です。eBPFデータパスが動いている証拠は、ドキュメントではなく、チェーンの数とマップのダンプだからです。

次のクイズで確認すること

このモジュールは概念だけを扱います。次のモジュールでアイデンティティモデルとkube-proxyの置き換えを扱いながら、上で見た値をHelm valuesファイルに自分で書き、その状態を検証するスクリプトまで作ります。