- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに
- Ciliumの位置づけ — CNI以上の存在
- eBPFデータパスの解剖 — パケットの旅路
- kube-proxy replacementの原理
- identityベースのセキュリティモデル
- トンネリング vs ネイティブルーティング
- IPAMモード
- インストールとアップグレードの実践
- kube-proxy代替の検証
- パフォーマンスの観点 — なぜ速くなるのか
- トラブルシューティングの基礎
- 運用上の注意点
- 導入チェックリスト
- おわりに
- 参考資料
はじめに
従来構成のKubernetesクラスタでは、サービスへのリクエスト1つがPodに到達するまでに数千のiptablesチェーンを通過します。サービスが5,000を超えるクラスタでは、ルール更新1回に数秒かかり、カーネルはパケットごとにほぼ線形探索に近いコストを支払います。Ciliumはこの経路をeBPFプログラムとハッシュマップで置き換え、サービス数に関係なくほぼO(1)のルックアップでパケットを処理します。
Ciliumは2023年10月にCNCFの卒業(Graduated)プロジェクトとなり、その後マネージドKubernetes陣営の標準CNIとして急速に定着しました。GKE Dataplane V2はCiliumベースであり、AKSにはAzure CNI Powered by Ciliumがあり、EKSでもCiliumを直接インストールしてkube-proxyを完全に排除する構成が一般的になりました。本記事ではCiliumのeBPFデータパスをパケットの旅路に沿って解剖し、kube-proxy replacement・identityセキュリティモデル・ルーティングモード・IPAM・インストールと検証・トラブルシューティングまで、運用者が知るべき内部を整理します。
Ciliumの位置づけ — CNI以上の存在
表面的にはCiliumはCNIプラグインですが、実際にカバーする領域ははるかに広いです。
| 領域 | 機能 | 置き換え対象 |
|---|---|---|
| Podネットワーキング | IP割り当て、Pod間ルーティング | 従来のCNI(flannel、calicoなど) |
| サービスロードバランシング | ClusterIP、NodePort、LoadBalancer | kube-proxy |
| ネットワークポリシー | L3/L4/L7ポリシー、DNSポリシー | NetworkPolicyと別途プロキシ |
| 可観測性 | フロー可視化(Hubble) | 別途モニタリングエージェント |
| マルチクラスタ | ClusterMesh | サービスメッシュの一部機能 |
| 暗号化 | WireGuard、IPsec | 別途オーバーレイソリューション |
これらすべての機能の共通基盤がeBPFです。eBPFは、カーネルの再コンパイルやモジュールのロードなしに、検証器(verifier)を通過したプログラムをカーネル内のフックポイントで実行できる技術です。ネットワーキングの観点で重要なフックは、XDP(ドライバレベル)とtc(トラフィックコントロール、L2/L3の入出力地点)です。
eBPFデータパスの解剖 — パケットの旅路
外部からNodePort経由で入ってきたパケットがPodに到達するまでの旅路を追ってみましょう。
[外部クライアント]
|
v
+---------------------------------------------------------------+
| ノード (Linuxカーネル) |
| |
| NIC受信 |
| | |
| v |
| [XDPフック] ──────── bpf_xdp.o |
| | - NodePort高速化、DDoSフィルタリング、LB(ドライバレベル) |
| | - ここでDROP/TX(折り返し)/PASSを決定 |
| v |
| [tc ingressフック] ── bpf_host.o (cil_from_netdev) |
| | - サービス変換: ClusterIP/NodePort -> バックエンドPod IP |
| | (cilium_lb4_services_v2, cilium_lb4_backends マップ) |
| | - conntrack記録 (cilium_ct4_global マップ) |
| | - ipcacheルックアップ: 宛先IP -> identity |
| v |
| ルーティング/リダイレクト (bpf_redirect_peer でveth越え) |
| | |
| v |
| [Pod lxcインターフェース] ── bpf_lxc.o (cil_to_container) |
| | - ポリシー評価: src identity + dst port/proto マッチ |
| | (エンドポイント別 cilium_policy_v2 マップ) |
| v |
| [Podネットワーク名前空間 -> アプリケーションソケット] |
+---------------------------------------------------------------+
重要なポイントを押さえると:
- XDPはNICドライバがパケットをsk_buffに変換する前に実行されます。メモリ割り当て前の段階のため最速であり、CiliumはNodePort/LoadBalancerの高速化(
loadBalancer.acceleration=native)やスタンドアロンL4LBモードで活用します。 - tcフックがCiliumデータパスの本体です。サービス変換、conntrack、ポリシー評価、トンネルカプセル化のすべてがここで行われます。
- bpf_redirect_peerは、ホスト側vethからPod名前空間内のピアデバイスへパケットを直接渡し、ソフトIRQの再スケジューリングなしに名前空間の境界を一度に越えます。
- ポリシー評価はIPではなくidentity(後述)を基準に行われます。
iptables経路との比較
同じNodePortリクエストがkube-proxy(iptablesモード)クラスタで処理される経路です。
NIC -> netfilter PREROUTING
-> KUBE-SERVICES チェーン (サービス数分のルールを線形走査)
-> KUBE-SVC-XXXX (確率ベースのDNAT分岐、バックエンド数分)
-> KUBE-SEP-XXXX (DNAT実行)
-> conntrack (nf_conntrack テーブル)
-> FORWARD チェーン -> CNIブリッジ/ルーティング -> veth -> Pod
| 項目 | iptables (kube-proxy) | eBPF (Cilium) |
|---|---|---|
| サービスルックアップ | ルールチェーンの線形走査 | ハッシュマップでO(1) |
| ルール更新 | テーブル全体の書き換え(サービスが多いほど遅い) | マップエントリ単位の増分更新 |
| バックエンド選択 | statisticモジュールの確率分岐 | ランダムまたはMaglev一貫性ハッシュ |
| conntrack | nf_conntrack(グローバル、ロック競合) | BPFマップベースの専用CT |
| ポリシー表現 | IP/CIDRベース | identityベース(ラベルの意味を保持) |
| L7認識 | 不可 | Envoy連携で可能 |
サービスが数百程度なら体感差は小さいですが、数千を超えるとiptablesの更新遅延と初回パケットのレイテンシが運用上の問題として表面化します。eBPFデータパスはこの2軸(ルックアップコスト、更新コスト)の両方を定数時間にします。
kube-proxy replacementの原理
Ciliumのkube-proxy replacement(KPR)は、Kubernetesのサービス抽象を2層のeBPFマップで実装します。
サービスルックアップの流れ (簡略化)
宛先 10.96.0.10:443 (ClusterIP)
|
v
cilium_lb4_services_v2 マップ
key: (IP, port, scope)
value: (backend count, rev_nat index, flags)
|
v
cilium_lb4_backends_v3 マップ
key: backend id
value: (pod IP, port, state)
|
v
DNAT実行 + cilium_lb4_reverse_nat に逆変換を記録
エージェントはKubernetes APIでService/EndpointSliceをwatchし、変更分のみをマップに反映します。データプレーンはカーネル内で完結しているため、エージェントが一時的に停止しても既存の接続と既存のサービス変換は動作し続けます。
DSRとMaglev
NodePortトラフィックがバックエンドのないノードに着信すると、別のノードへもう1ホップ発生します。デフォルトのSNATモードでは応答が再び入口ノードを経由して戻りますが、**DSR(Direct Server Return)**モードではバックエンドPodがクライアントに直接応答し、応答経路のホップと帯域消費を削減し、クライアントのソースIPも保持されます。
Maglev一貫性ハッシュはGoogleが発表したL4ロードバランサのアルゴリズムで、バックエンドの増減時にも既存フローの大部分が同じバックエンドにマッピングされ続けるようにします。複数ノードがECMPで同じVIPトラフィックを受ける構成では、ノード間でバックエンド選択が一貫し、ノード障害時の接続切断を最小化します。
# helm values - KPR + DSR + Maglev の例
kubeProxyReplacement: true
loadBalancer:
mode: dsr
algorithm: maglev
acceleration: native # XDP高速化 (対応NICのみ)
maglev:
tableSize: 16381 # バックエンド数 x 100 より大きい素数を推奨
DSRはネイティブルーティングモードで最も自然に動作し、トンネルモードと組み合わせる場合はGeneve DSRなどの別オプションが必要になる点を覚えておいてください。
identityベースのセキュリティモデル
Ciliumセキュリティモデルの核心は「IPではなくidentityで判断する」ことです。
Podラベル identity (数値)
--------------------------- ----------------
app=frontend, env=prod ---> identity 51234
app=backend, env=prod ---> identity 60917
(予約) host ---> 1
(予約) world ---> 2
(予約) remote-node ---> 6
ipcacheマップ: IP/CIDR -> identity
10.0.1.23/32 -> 51234
10.0.2.40/32 -> 60917
0.0.0.0/0 -> 2 (world)
動作の順序は次のとおりです。
- Podが作成されると、エージェントがセキュリティ関連のラベル集合を抽出し、同一のラベル集合には同一の数値identityを割り当てます(kvstoreまたはCRDによるグローバル合意)。
- すべてのノードの
cilium_ipcacheマップに、該当PodのIPとidentityのマッピングが伝播されます。 - パケット送信時、ソースidentityはメタデータ(トンネルヘッダまたはパケットマーク)として運ばれるか、受信側でipcacheルックアップにより復元されます。
- 受信エンドポイントのポリシーマップは「identity 51234がTCP 8080にアクセスできるか」をO(1)で判定します。
このモデルの利点は、ポリシーの意味がIPの変動と無関係に維持されることです。Podが再スケジュールされてIPが変わっても、ラベルが同じならidentityも同じで、ポリシーマップを修正する必要はありません。ipcacheの1箇所だけが更新されれば済みます。
# identityとipcacheを直接確認
kubectl -n kube-system exec ds/cilium -- cilium identity list
kubectl -n kube-system exec ds/cilium -- cilium bpf ipcache list
kubectl -n kube-system exec ds/cilium -- cilium endpoint list
トンネリング vs ネイティブルーティング
Pod間のパケットがノード境界を越える方法は大きく2つあります。
トンネルモード (VXLAN/Geneve) ネイティブルーティング
+--------+ カプセル化 +--------+ +--------+ 素のIP +--------+
| node A | ==========> | node B | | node A | --------> | node B |
+--------+ UDP 8472 +--------+ +--------+ ルータ/BGP +--------+
Podパケットを外部ヘッダで包む ネットワークがPodCIDRの経路を知る必要
| 基準 | VXLAN | Geneve | ネイティブルーティング (BGP/クラウド) |
|---|---|---|---|
| ネットワーク要件 | ノード間UDP 8472の許可のみ | ノード間UDP 6081の許可のみ | アンダーレイがPodCIDRをルーティング可能であること |
| オーバーヘッド | 約50バイトのカプセル化 | 約50バイト以上(可変オプション) | なし |
| MTUへの影響 | あり(MTU縮小が必要) | あり | なし |
| DSR親和性 | 限定的 | DSRオプションの運搬に有利 | 最も自然 |
| 運用難易度 | 低い | 低い | BGPまたはクラウドルーティングの理解が必要 |
| 適した環境 | アンダーレイを制御できない環境 | メタデータ拡張が必要な場合 | オンプレBGP、ENIなどクラウドネイティブ |
選択基準をざっくりまとめると:
- アンダーレイネットワークを制御できない場合(社内共用網、単純なL3環境)→ トンネルモードから始める
- オンプレでToRスイッチとBGPピアリングが可能 → ネイティブルーティング + BGP Control Plane
- AWS/AzureでENI/Azure IPAMを使う → ネイティブルーティングが基本前提
# ネイティブルーティング + BGP の例 (helm values)
routingMode: native
ipv4NativeRoutingCIDR: 10.0.0.0/8
autoDirectNodeRoutes: true # 同一L2の場合にノード間直接経路を設置
bgpControlPlane:
enabled: true # CiliumBGPPeeringPolicy/ClusterConfig を使用
IPAMモード
Pod IPをどこからどう割り当てるかも、データパス設計の一部です。
| IPAMモード | 割り当て主体 | 特徴 |
|---|---|---|
| cluster-pool (デフォルト) | Cilium operator | CiliumNode CRDでノード別PodCIDRを分配、柔軟なプールサイズ |
| kubernetes | kube-controller-manager | Node.spec.podCIDRを使用、既存クラスタの慣行と互換 |
| eni | AWS ENI | PodにVPCネイティブIPを付与、ルーティングモードはnative |
| azure | Azure IPAM | Azure CNI Powered by Ciliumの基盤 |
| multi-pool | Cilium operator | 名前空間/ノードごとに異なるプールを使用可能 |
cluster-poolモードで最初にプールを小さく取りすぎると、ノード増設時にCIDR枯渇でPodのスケジューリングが止まる可能性があるため、clusterPoolIPv4PodCIDRListは将来のノード数まで考慮して余裕を持たせるべきです。
インストールとアップグレードの実践
カーネル要件
| 機能 | 最小カーネル |
|---|---|
| 基本データパス | 4.19以上(実質的には5.4以上を推奨) |
| WireGuard暗号化 | 5.6以上 |
| XDP高速化 | NICドライバの対応 + 5.x推奨 |
| BIG TCP、netkitなどの新機能 | 6.x系 |
2026年現在、主要ディストリビューション(RHEL 9、Ubuntu 22.04/24.04)はすべて5.14以上のため通常は問題ありませんが、古いオンプレミスノードは必ずuname -rで確認してください。
helmインストール例
helm repo add cilium https://helm.cilium.io/
helm repo update
# kube-proxyなしでクラスタを作成したか、削除済みであることを想定
helm install cilium cilium/cilium \
--version 1.18.5 \
--namespace kube-system \
-f values.yaml
# values.yaml — kube-proxy代替 + Hubble有効化の基本形
kubeProxyReplacement: true
k8sServiceHost: api.mycluster.internal # KPR時はAPIサーバの直接指定が必須
k8sServicePort: 6443
routingMode: tunnel
tunnelProtocol: vxlan
ipam:
mode: cluster-pool
operator:
clusterPoolIPv4PodCIDRList:
- 10.128.0.0/12
clusterPoolIPv4MaskSize: 24
hubble:
enabled: true
relay:
enabled: true
ui:
enabled: true
operator:
replicas: 2
prometheus:
enabled: true
k8sServiceHostを指定する理由が重要です。kube-proxyがない場合、ClusterIPの変換はCiliumが担当しますが、Ciliumエージェント自身が起動する前はkubernetes.defaultのClusterIPを解決できません。鶏と卵の問題を避けるために、APIサーバの実アドレスを直接教えるのです。
cilium-cliの活用
# インストール状態の総合チェック
cilium status --wait
# クラスタ全体の接続性テスト (テストPodを自動デプロイ)
cilium connectivity test
# 設定の確認
cilium config view | grep -i kube-proxy
アップグレード手順
# 1) リリースノートのアップグレードガイドを必ず確認 (マイナーバージョンの飛ばしは禁止)
# 2) pre-flight検査で新イメージの事前プルとCRD互換性を確認
helm install cilium-preflight cilium/cilium --version 1.18.5 \
--namespace kube-system \
--set preflight.enabled=true \
--set agent=false --set operator.enabled=false
# 3) preflight正常確認後に本アップグレード
helm upgrade cilium cilium/cilium --version 1.18.5 \
--namespace kube-system -f values.yaml
# 4) ローリング再起動の状態を観察
kubectl -n kube-system rollout status ds/cilium
アップグレード時、エージェントPodが再起動してもeBPFプログラムとマップはカーネルに残るため、既存トラフィックが途切れないのが正常です。ただしマップレイアウトが変わるメジャーな変更では一時的な再生成が発生し得るため、リリースノートの確認が必須です。
kube-proxy代替の検証
KPRが実際に動作しているか、必ず自分の目で確認すべきです。
# 1) KPRモードの確認 - "True" 表示を確認
kubectl -n kube-system exec ds/cilium -- cilium status --verbose | grep -A3 KubeProxyReplacement
# 2) サービスがeBPFマップに入ったか確認
kubectl -n kube-system exec ds/cilium -- cilium service list
kubectl -n kube-system exec ds/cilium -- cilium bpf lb list
# 3) kube-proxyが本当にないか、iptablesの痕跡を確認
kubectl -n kube-system get ds kube-proxy 2>&1 || echo "kube-proxyなし - 正常"
iptables-save | grep -c KUBE-SVC || echo "KUBE-SVCチェーンなし - 正常"
# 4) 実際の接続テスト
kubectl run probe --image=curlimages/curl --rm -it --restart=Never -- \
curl -s -o /dev/null -w "%{http_code}\n" http://my-service.default.svc.cluster.local
特に既存クラスタからkube-proxyを削除して移行する場合、残存するiptablesルールがeBPF経路と衝突し得るため、kube-proxy DaemonSet削除後にノードの残存KUBE-*チェーンを整理する手順(ノード再起動またはiptablesフラッシュ)を計画に含めるべきです。
パフォーマンスの観点 — なぜ速くなるのか
ベンチマーク数値は環境依存性が大きいため、構造的にどこで利得が生まれるかを理解することが重要です。
- ルックアップ計算量: iptablesはルール数に比例した走査、eBPFはハッシュマップで定数時間。サービス/ポリシー数が増えるほど差が広がります。
- 経路長の短縮: bpf_redirect_peerでvethペア通過時にソフトIRQ1サイクルを節約し、ホストルーティングモードでは上位netfilterスタックへの進入自体をスキップします。
- 更新コスト: デプロイが頻繁なクラスタでiptablesの全面書き換えはCPUスパイクとルール適用遅延を生みますが、マップの増分更新はほぼ無コストです。
- XDP: ドライバレベルの処理でsk_buff割り当て前にLB/ドロップを決定し、NodePortパケットの処理量を大幅に引き上げます。
逆にコストもあります。L7ポリシーを有効にすると該当トラフィックはユーザ空間のEnvoyを経由するためレイテンシが追加され、トンネルモードはカプセル化オーバーヘッドとMTU縮小を伴います。「すべてが速くなる」のではなく「どの機能を有効にするとどのコストがかかるか」を把握して選択するのが運用の核心です。
トラブルシューティングの基礎
# リアルタイムのデータパスイベント観察 (ドロップ理由を含む)
kubectl -n kube-system exec ds/cilium -- cilium monitor --type drop
kubectl -n kube-system exec ds/cilium -- cilium monitor --type policy-verdict
# 特定エンドポイントの詳細 (ポリシー状態、identityの確認)
kubectl -n kube-system exec ds/cilium -- cilium endpoint list
kubectl -n kube-system exec ds/cilium -- cilium endpoint get 1234
# conntrack/NATマップの直接照会
kubectl -n kube-system exec ds/cilium -- cilium bpf ct list global | head
kubectl -n kube-system exec ds/cilium -- cilium bpf nat list | head
# 総合診断バンドルの収集 (イシューレポート添付用)
cilium sysdump
# またはノード単位で
kubectl -n kube-system exec ds/cilium -- cilium-bugtool
cilium monitorのドロップ理由コードが第一の手がかりです。よく見る理由は次のとおりです。
| ドロップ理由 | よくある原因 |
|---|---|
| Policy denied | ポリシー未許可 — identityとポートを再確認 |
| CT: Map insertion failed | conntrackマップ満杯 — bpf-ct-global-tcp-maxを調整 |
| Unsupported L3 protocol | 非IPトラフィック — 意図したものか確認 |
| Stale or unroutable IP | ipcache不一致 — エージェント/ノード間の同期を点検 |
| Missed tail call | プログラムロード不一致 — エージェント再起動、バージョン混在を確認 |
運用上の注意点
- バージョン互換: Ciliumのマイナーバージョンは順次アップグレードのみサポートします。1.16から1.18への飛ばしは不可です。Kubernetesバージョンのサポートマトリクスも併せて確認してください。
- ポリシー移行: Calicoなどから移行する際、既存のNetworkPolicyはほとんどそのまま動作しますが、identityモデルの違いで挙動が微妙に変わり得る部分(特にipBlockとノードIPの扱い)はステージングで先に検証すべきです。
- 予約identity: host、remote-node、world、kube-apiserverといった予約identityの意味を理解していないと、ノード発のトラフィックやヘルスチェックがポリシーにブロックされる事故が起きます。
- リソース上限: 大規模クラスタではBPFマップサイズ(ct、ipcache、lbマップ)のデフォルト値を点検し、エージェントのメモリ要求をそれに合わせて調整すべきです。
- マネージド環境の制約: GKE Dataplane V2、AKSのCiliumモードではhelm値の一部がクラウド側で固定されています。セルフインストールと同じ自由度は期待できません。
導入チェックリスト
- ノードのカーネルバージョンが5.4以上か(WireGuardが必要なら5.6以上)
- ルーティングモードの決定(トンネル vs ネイティブ)とその根拠を文書化したか
- PodCIDRプールが今後3年のノード増設に耐えられるか
- kubeProxyReplacement時にk8sServiceHost/Portを指定したか
- トンネルモードならノード間でUDP 8472(VXLAN)または6081(Geneve)が開いているか
- MTU計算(カプセル化/暗号化オーバーヘッドの反映)を済ませたか
- cilium connectivity testが全項目パスするか
- kube-proxy削除後の残存iptablesチェーン整理手順があるか
- cilium status、BPFマップ使用率、ドロップカウントをモニタリングに接続したか
- アップグレード時のpreflight手順がランブックに含まれているか
おわりに
Ciliumの本質は「Kubernetesネットワーキングの意味論(サービス、ラベル、ポリシー)をカーネル内のデータ構造へ直接下ろしたこと」です。iptables時代にはラベルという意味がIPルールへの翻訳の過程で失われていましたが、eBPFデータパスではidentityという形でカーネルまで保持されます。この構造を理解すれば、kube-proxy replacement、ポリシー評価、トラブルシューティングがすべて1つの絵としてつながります。次回はこの上に乗るネットワークポリシー(L3〜L7、DNS)を実践YAML中心に扱います。
参考資料
- Cilium公式ドキュメント: https://docs.cilium.io/
- Cilium kube-proxy replacementガイド: https://docs.cilium.io/en/stable/network/kubernetes/kubeproxy-free/
- Ciliumルーティングモードのドキュメント: https://docs.cilium.io/en/stable/network/concepts/routing/
- eBPF公式サイト: https://ebpf.io/
- LinuxカーネルBPFドキュメント: https://www.kernel.org/doc/html/latest/bpf/
- Kubernetes Service公式ドキュメント: https://kubernetes.io/docs/concepts/services-networking/service/
- CNCF Cilium卒業発表: https://www.cncf.io/announcements/2023/10/11/cloud-native-computing-foundation-announces-cilium-graduation/
- VXLAN RFC 7348: https://datatracker.ietf.org/doc/html/rfc7348
- Geneve RFC 8926: https://datatracker.ietf.org/doc/html/rfc8926
- Cilium GitHubリポジトリ: https://github.com/cilium/cilium
- Envoyプロキシ公式ドキュメント: https://www.envoyproxy.io/docs