Claude が書いた記事
Cilium ってなんやねん? ── eBPF が『壁を越えない』速さと、身元 ID を載せて運ぶ仕掛け
「cilium って何?」から始めた学習ログ。eBPF とはカーネル内で安全にプログラムを動かすことができる土台のことで、Cilium はその土台の上に建てた k8s 向けのプログラム。ユーザー空間ではなくカーネル空間で動作させることができるため、高速な通信処理ができる。
俺の最初の疑問
ふと「cilium って何?」と気になった。ニュースやら k8s の文脈やらでよく見るが、腹落ちしていない。
俺はネットワークの技術サポートをやっている。Azure の Application Gateway / Load Balancer / VNet / Front Door あたりが守備範囲で、最近は k8s の overlay やら east-west をかじり始めたところ。だから Cilium も「k8s のネットワーク系の何か」くらいの解像度しかなかった。
素朴な疑問を順に潰していったら、「カーネルの中でパケットを捌く」という、俺が慣れ親しんでいるネットワーク技術とは別レイヤーの話だった。しかも掘っていくと、最後は Azure の SDN とまったく同じ骨格に着地した。その記録。
まず一言でいうと
eBPF = Linux カーネルの中で、自作の小さなプログラムを安全に動かせる仕組み。Cilium = その eBPF を使って建てた、Kubernetes 向けのネットワーク / セキュリティの完成品。
そして eBPF の速さの正体は一行で言える。
パケット (データ) をユーザー空間まで運ばず、カーネルの中で通す / 落とす / 転送まで判断し終えること。
このカーネル空間の中で動作させることこそ、今日いちばん腹落ちしたところだった。
何と比べるとわかるか
二段階で比較すると一気に見通しが良くなった。
① 従来のパケット処理 vs eBPF (壁を越えるか)
Linux はメモリと実行環境が カーネル空間 (OS の中核。ハードウェアに直結できる特権の世界) と ユーザー空間 (普通のアプリが動く世界) に分かれていて、両者は壁で隔離されている。
| 従来 | eBPF | |
|---|---|---|
| 処理する場所 | ユーザー空間のアプリまで運ぶ | カーネル空間の中でその場で判断 |
| 壁の往復 | 行き帰りで 2 回 (コピー + コンテキストスイッチ) | 越えない (往復ゼロ) |
| 速さ | パケットが大量だと往復が積もって遅い | 速い |
② eBPF vs Cilium (土台か完成品か)
ここは「どっちがいい」と比べるものではなかった。レイヤーが違う。
- eBPF = 小麦粉。汎用の素材。それ単体では仕事をしない。自分でプログラムを書いて仕込む必要がある。
- Cilium = パン屋の食パン。その小麦粉で焼いた完成品。買ってすぐ使える。
同じ小麦粉を使う店は他にもある (Falco=セキュリティ、Pixie=可観測性、Katran=Meta のロードバランサ)。Cilium はその中の有力な一つ、という位置づけ。
何が問題なのか
「ユーザー空間にコピーする」が地味に効く。普通の TCP 処理だと、パケットはまずカーネルに届くが、処理したいアプリ (ファイアウォールやパケット解析) はユーザー空間にいる。壁で隔離されているので、データを複製して壁の向こうへ渡す (コピー) + カーネルとユーザー空間を行き来する (コンテキストスイッチ) が要る。
パケットが毎秒何百万個も飛んでくると、この「コピー + 行き来」の積み重ねが大きなオーバーヘッドになる。k8s でサービスが数百個に増えると、従来の iptables ベースのルーティングはルールが膨らんで遅延し始める。eBPF はカーネル内で完結するから、ここを高速に捌ける。
「書類を別の部署に運んで判子をもらって戻す」のではなく、「その場で判断して即処理する」。これが eBPF。
図で見る
1. ベースとなる概念:ユーザー空間とカーネル空間の壁
2. eBPF と Cilium の関係:土台と完成品 (小麦粉とパン)
3. Cilium の構成:職人 (agent) と機械 (eBPF) の役割分担
4. ノードまたぎ:身元 ID (identity) を載せて運ぶ
混乱しやすいポイント
俺が実際に引っかかって直された点。
① cilium-agent はカーネルに常駐していない
「カーネルで動く」と聞くと agent 自体がカーネルにいる気がするが、違う。agent はユーザー空間の普通のプロセス (デーモン)。カーネルで動くのは、agent が仕込んだ eBPF の方。職人 (agent) は設計図を読んで機械 (eBPF) を据え付けるが、現場 (カーネル) に住み着くわけではない。だから agent が落ちても、すでに仕込まれた eBPF はカーネルで動き続ける。
ネットワーク屋の感覚で言うと、cilium-agent は bird や frr(ルーティングデーモン) と同じポジションだ。OS の上に常駐して、設定 (k8s API=設計図) を見て、実際の転送ルール (bird なら FIB、Cilium なら eBPF) を書き換え続けるデーモン。
② アプリ Pod もユーザー空間にいる
これも俺が間違えたところ。アプリ Pod の中身 (コンテナ=普通のプロセス) はユーザー空間で動く。カーネル空間にいるのは eBPF だけ。Pod の「通信」がカーネルに下りてきて eBPF に捌かれるだけで、Pod 自身がカーネルに住んでいるわけではない。
③ eBPF は「プロセス」ではない
プロセスはユーザー空間で動く実行単位。eBPF は カーネル内のフックに取り付けられて、イベント発火時だけ動く実行コード。だから ps で並ぶようなものではない。
④ カプセル化を「誰が」やるのか
ノードまたぎで VXLAN / Geneve に包むのは誰か。答えは カーネル側 (eBPF + カーネルの VXLAN 機能) が実行する。cilium-agent は設定を仕込むだけで、パケット 1 枚ごとには登場しない。もし毎パケット職人が出てきたら、それこそ壁を往復して遅くなる (1 枚目の話に戻る)。
⑤ 「Cilium をやる」に C 言語は要らない
eBPF の中身は制限付き C (xxx.bpf.c) で書かれているが、それを書いて仕込むのは Cilium の仕事。使う側 (大多数) がやるのは k8s の知識・YAML でポリシーを書く・CLI を叩くだけ。C が要るのは Cilium 本体に貢献する / 独自の eBPF を自作する側 (+ Go も要る)。サクッと自分で eBPF を書きたいだけなら bpftrace(.bt、awk 風) という軽い道だ。
⑥ eBPF は k8s 専用じゃない (Linux の機能)
ここを分けておかないと「eBPF=k8s の何か」と誤解する。eBPF は Linux カーネルの汎用機能で、k8s も Docker も要らない (新しめのカーネルがあれば動く。今は Windows 版 ebpf-for-windows まである)。k8s / Cilium は、その eBPF を使う数ある消費者の一つにすぎない。
ネットワーク屋として効くのは XDP の例だ。NIC ドライバの一番手前で eBPF を動かし、攻撃パケットをカーネルに入る前に叩き落とす (Cloudflare の DDoS 防御や L4 ロードバランサ Unimog がこれ)。前にやった CDN / Cloudflare の話 の、さらに下のレイヤーで eBPF が効いている。
たとえ話
3 つのたとえが効いた。
- 小麦粉とパン (eBPF と Cilium)。素材と完成品。レイヤーが違うので「どっちがいい」と比べない。
- 職人と機械 (agent と eBPF)。職人 (agent・ユーザー空間) が設計図を読んで機械 (eBPF・カーネル) を据え付ける。据え付けた後は機械が自動で動き続け、職人が離れても動く。
- VFP (Azure) と Cilium (ノードまたぎ)。ここがネットワーク屋として一番でかかった。Cilium が「身元 ID を VXLAN に載せて運ぶ」のは、Azure の SDN が VFP でテナントを分離して運ぶのと同じ骨格だった。
| Azure SDN (俺の土俵) | Cilium |
|---|---|
| カプセル化を実行する VFP (ホストのデータパス=カーネル / vSwitch 側) | eBPF + カーネルの VXLAN 機能 |
| VXLAN / NVGRE | VXLAN / Geneve |
| テナント / VNet を識別する VNI | 身元 ID (security identity=ラベルの数値化) |
| ポリシーを配るコントロールプレーン | cilium-agent + k8s API |
cilium-agent = コントロールプレーン側、eBPF+カーネル = VFP のデータパス側。両方ともコントロールプレーンはパケット 1 枚ごとには出てこない。ここがピタッと重なった瞬間に、Cilium が知らない技術じゃなくなった。(east-west の overlay 自体は前回のPod 間通信と overlay で掴んだ続きでもある。)
ニュースを読むための変換表
| 言葉 | つまり何の話? |
|---|---|
| eBPF | Linux カーネル内で自作プログラムを安全に動かす仕組み。検証器が事前チェック。汎用の土台 |
| Cilium | eBPF を使った k8s 向けネットワーク / セキュリティの完成品。CNCF Graduated |
| カーネル空間 / ユーザー空間 | OS の中核 (特権・ハード直結) / 普通のアプリの世界。壁で隔離されている |
| cilium-agent | 各ノード常駐のプロセス (職人)。eBPF を仕込む。DaemonSet で 1 ノード 1 個 |
| cilium-operator | クラスタ全体で数個動く管理役。ノード数と無関係 |
| Hubble | Cilium の可視化機能。サービス間通信をマップで見る |
| security identity | ラベルを数値化した「身元」。IP でなくこれで通信制御。ノードまたぎで載せて運ぶ |
| DaemonSet | 全ノードに 1 個ずつ必ず配る k8s の仕組み |
| VXLAN / Geneve | ノード間で身元 ID と元パケットを包んで運ぶカプセル (オーバーレイ) |
| WireGuard (Cilium 透過暗号化) | ノードをまたぐ区間だけ、アプリ無改修で通信を暗号化 |
| bpftrace / .bt | eBPF を awk 風スクリプトでサクッと書く道具 |
壁を越えない速さと、Azure の VFP と同じ骨格まで掴んだ。次は設計者として「で、自分なら kube-proxy のまま粘るか、Cilium に替えるか?」。
- Service が数百〜数千に増えたとき、kube-proxy (iptables) のまま粘るか eBPF (Cilium) に替えるか、即答できるか。 判断軸は「Service 数 × iptables のルール線形探索コスト × 運用の入れ替えコスト」。小規模なら移行コストの方が高い。
- 責任境界:パケットの行き先を決めてるのは誰か ── カーネル (eBPF・データパス) か、cilium-agent + k8s API (コントロールプレーン・設定) か。 障害時に「agent が落ちた」と「eBPF が壊れた」を切り分けられるか (agent が落ちても eBPF は流れ続ける)。
これに答えられると強い。「Cilium を知ってる」の一歩先 ── 規模から CNI を選び、コントロールプレーンとデータパスのどっちの障害かを切り分けられる側に立てる。Azure の VFP で掴んだ「決めるソフト / 流すハード」がそのまま効く。
- kube-proxy / iptables の置き換え ── 規模で遅くなる iptables を、eBPF が east-west の Service ルーティングでどう肩代わりするか。次の一歩。
- north-south の Cilium (Ingress / Gateway API) ── 入口側を Cilium で見る。AGC の north-south の続き。
- security identity の正体 ── ラベルがどう数値 ID に変わり、ノード間で同期されるか。Azure の VNI と並べる。
- Hubble で通信を見る ── kind / minikube に Cilium を入れ、ポリシー違反を可視化する手を動かす入口。
- bpftrace で eBPF を 1 本書く ──
opensnoop的な数行から、土台をこねて壁を越えない速さを体感する。