8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Cilium + HubbleでeBPF時代のK8sネットワーク可視化を体験してみた

Last updated at Posted at 2025-12-15

はじめに

2025年7月29日、Cilium 1.18がリリースされました。

3298コミット、955人以上のコントリビューター、GitHub Stars 22,000超え。CNCFのGraduatedプロジェクトとして、Kubernetesネットワークの世界で存在感を増しています。

「eBPFがアツい」「Ciliumがkube-proxyを置き換える」そんな話を聞きつつも、なかなか手を動かせていなかったので、この機会にローカル環境で試してみました。

この記事では、kindを使ってCilium + Hubbleを構築し、eBPFベースのネットワーク可視化を体験するまでの手順を紹介します。

Ciliumってなに?

Ciliumは、eBPF(extended Berkeley Packet Filter)を基盤としたCNI(Container Network Interface)プラグインです。

従来のCNI(Flannel、Calico等)との違い

従来のKubernetesネットワークはiptablesでパケット処理を行っていました。

◼︎従来のフロー
パケット → iptables → ユーザー空間 → 判定 → カーネル → 転送

iptablesはルール数が増えると線形に遅くなり、大規模クラスタではボトルネックになりがちです。一方、CiliumはeBPFを使ってカーネル内で直接パケット処理を行います。

◼︎Ciliumのフロー
パケット → カーネル内のeBPFプログラム → 転送
項目 従来(iptables) Cilium(eBPF)
パケット処理 ユーザー空間 ↔ カーネル空間を行き来 カーネル内で完結
ルール数増加時 線形に遅くなる 影響が少ない
可視化 別ツールが必要 Hubble統合
L7ポリシー 実装が難しい ネイティブ対応
kube-proxy 必要 置き換え可能

eBPFとは

eBPFは、カーネルを再コンパイルせずに、カーネル内でカスタムプログラムを実行できる技術です。
image.png

従来のカーネル拡張との違い

方法 特徴 リスク
カーネル再コンパイル 機能追加のたびにカーネルをビルド 運用負荷大、互換性問題
カーネルモジュール 動的にロード可能 バグでカーネルパニックの可能性
eBPF 検証器でチェック後にカーネル内で実行 安全性が担保される

eBPFの仕組み

eBPFプログラムは 検証器(Verifier) によって安全性がチェックされるため、カーネルをクラッシュさせるようなコードは実行前にリジェクトされます。
image.png
https://ebpf.io/ja/what-is-ebpf/#%E6%A4%9C%E8%A8%BC から抜粋

もともとはパケットフィルタリング用途のようでしたが、現在ではネットワーク、セキュリティ、オブザーバビリティなど幅広い用途で使われており、Netflix、Google、Metaなど大規模なトラフィックを捌く企業で採用が進んでいます。

Hubbleとは

Hubbleは、Ciliumに統合されたネットワーク可視化・オブザーバビリティツールです。

従来のKubernetesネットワーク可視化の課題

Kubernetesのネットワークトラブルシューティングは大変でした。「このPodはどこと通信してる?」「なぜ通信が失敗してる?」を調べるには、以下のような方法が必要でした。

方法 概要 課題
tcpdump / Wireshark 手動でパケットキャプチャ 大規模クラスタでは非現実的、Pod特定が困難
Envoy Sidecar(Istio等) 各Podにプロキシを注入して通信を観測 全Podにサイドカー必要、リソースオーバーヘッド大
Datadog / New Relic等 SaaS型のAPM/オブザーバビリティ エージェント導入が必要、コストがかかる
アプリへのログ埋め込み 自前で通信ログを実装 コード変更が必要、開発工数がかかる

Hubbleのアプローチ

HubbleはeBPFを活用してカーネルレベルで通信を観測します。

特徴 説明
サイドカー不要 Podへの変更なしで全トラフィックを観測
低オーバーヘッド カーネル内で処理するためCPU/メモリ消費が少ない
コード変更不要 アプリケーションに手を加えずに可視化
L3/L4/L7対応 TCP接続からHTTPリクエストまで可視化可能

Hubbleを使えば、以下のことがUIやCLIで簡単に確認できます。

  • リアルタイムのトラフィック監視:どのPodがどこと通信しているか
  • サービスマップ:依存関係の可視化
  • NetworkPolicyの動作確認:許可/拒否がひと目でわかる
  • L7レベルの観測:HTTPリクエスト、gRPCコールなど
    image.png
    https://github.com/cilium/hubble から引用

Cilium 1.18の主な新機能

今回のリリースでは、以下のような機能が追加されています。

ネットワーク

  • ロードバランシングの再設計:メモリ使用量の削減と拡張性の向上
  • Ingress帯域制限:bandwidth managerでIngress方向のレート制限が可能に
  • 複数Egress Gateway:1つのポリシーで複数のゲートウェイノードを指定可能

IPv6

  • トンネルモードでIPv6アンダーレイ対応:IPsec暗号化と組み合わせ可能
  • IPv6フラグメント対応:順序付きIPv6フラグメントの処理に対応

オブザーバビリティ

  • Hubble CLIでポリシー名表示:どの(C)CNPが通信を許可/拒否したかが見える
  • カプセル化トラフィックのデコード:より深い可視化

パフォーマンス

  • ポリシー・サービス実装が最大45%高速化
  • Dockerイメージサイズ32%削減(arm64)

詳細はリリースノートをご参照ください。

環境構築

それでは実際に動かしてみます。kindを使えば30分程度で環境構築からHubbleでの可視化まで試せます。

前提条件

  • Docker Desktop(またはDocker Engine)
  • kind
  • Homebrew(Macの場合)

1. Cilium CLIのインストール

brew install cilium-cli

インストール確認

cilium version --client
cilium-cli: v0.18.9 compiled with go1.25.5 on darwin/arm64
cilium image (default): v1.18.3
cilium image (stable): v1.18.4

2. kindクラスタの作成(CNIなし)

CiliumをCNIとして使うため、kindのデフォルトCNIを無効化してクラスタを作成します。
(事前にDocker Engineを起動します)

cat <<EOF | kind create cluster --name cilium-demo --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
networking:
  disableDefaultCNI: true
  kubeProxyMode: none
nodes:
  - role: control-plane
  - role: worker
  - role: worker
EOF

設定のポイント

  • disableDefaultCNI: true:kindのデフォルトCNI(kindnet)を無効化
  • kubeProxyMode: none:kube-proxyも無効化(CiliumがeBPFで代替)
  • workerノード2台:Pod間通信を試すため

クラスタ作成後、PodはPending状態になります。
CNIがまだインストールされていないためで、これは正常な状態です。次のステップでCiliumをインストールするとRunningになります。

kubectl get pods -A
NAMESPACE            NAME                                                READY   STATUS    RESTARTS   AGE
kube-system          coredns-5d78c9869d-llfq5                            0/1     Pending   0          46s
kube-system          coredns-5d78c9869d-prnqh                            0/1     Pending   0          46s
kube-system          etcd-cilium-demo-control-plane                      1/1     Running   0          62s
kube-system          kube-apiserver-cilium-demo-control-plane            1/1     Running   0          62s
...

3. Ciliumのインストール

Hubble UIも一緒に有効化してインストールします。

cilium install --set hubble.relay.enabled=true --set hubble.ui.enabled=true
# 出力結果
🔮 Auto-detected Kubernetes kind: kind
ℹ️  Using Cilium version 1.18.3
🔮 Auto-detected cluster name: kind-cilium-demo
ℹ️  Detecting real Kubernetes API server addr and port on Kind
🔮 Auto-detected kube-proxy has not been installed
ℹ️  Cilium will fully replace all functionalities of kube-proxy

...魔法みたいな絵文字が出てきてワクワクします。
インストール完了まで待機します。

cilium status --wait
    /¯¯\
 /¯¯\__/¯¯\    Cilium:             OK
 \__/¯¯\__/    Operator:           OK
 /¯¯\__/¯¯\    Envoy DaemonSet:    OK
 \__/¯¯\__/    Hubble Relay:       OK
    \__/       ClusterMesh:        disabled

DaemonSet              cilium                   Desired: 3, Ready: 3/3, Available: 3/3
DaemonSet              cilium-envoy             Desired: 3, Ready: 3/3, Available: 3/3
Deployment             cilium-operator          Desired: 1, Ready: 1/1, Available: 1/1
Deployment             hubble-relay             Desired: 1, Ready: 1/1, Available: 1/1
Deployment             hubble-ui                Desired: 1, Ready: 1/1, Available: 1/1
Containers:            cilium                   Running: 3
                       cilium-envoy             Running: 3
                       cilium-operator          Running: 1
                       clustermesh-apiserver    
                       hubble-relay             Running: 1
                       hubble-ui                Running: 1
Cluster Pods:          5/5 managed by Cilium
Helm chart version:    1.18.3
Image versions         cilium             quay.io/cilium/cilium:v1.18.3@sha256:5649db451c88d928ea585514746d50d91e6210801b300c897283ea319d68de15: 3
                       cilium-envoy       quay.io/cilium/cilium-envoy:v1.34.10-1761014632-c360e8557eb41011dfb5210f8fb53fed6c0b3222@sha256:ca76eb4e9812d114c7f43215a742c00b8bf41200992af0d21b5561d46156fd15: 3
                       cilium-operator    quay.io/cilium/operator-generic:v1.18.3@sha256:b5a0138e1a38e4437c5215257ff4e35373619501f4877dbaf92c89ecfad81797: 1
                       hubble-relay       quay.io/cilium/hubble-relay:v1.18.3@sha256:e53e00c47fe4ffb9c086bad0c1c77f23cb968be4385881160683d9e15aa34dc3: 1
                       hubble-ui          quay.io/cilium/hubble-ui-backend:v0.13.3@sha256:db1454e45dc39ca41fbf7cad31eec95d99e5b9949c39daaad0fa81ef29d56953: 1
                       hubble-ui          quay.io/cilium/hubble-ui:v0.13.3@sha256:661d5de7050182d495c6497ff0b007a7a1e379648e60830dd68c4d78ae21761d: 1

全てOKになっていれば成功です!
(筆者はDockerのディスク容量が足りずエラーとなったので、不要リソースを削除して待機したところ、Ciliumのイメージが正常に起動されました)

4. Hubble CLIのインストール

brew install hubble

Hubble Relayに接続できるようポートフォワードを設定します。

cilium hubble port-forward &

接続確認

hubble status
# 出力結果
Healthcheck (via localhost:4245): Ok
Current/Max Flows: 5,612/12,285 (45.68%)
Flows/s: 16.07
Connected Nodes: 3/3

実践:トラフィックを可視化してみる

サンプルアプリのデプロイ

通信を可視化するためのシンプルなアプリをデプロイします。

# curlが使えるクライアントPod
kubectl create deployment client --image=curlimages/curl -- sleep infinity

# レスポンスを返すサーバーPod
kubectl create deployment server --image=traefik/whoami
kubectl expose deployment server --port=80

Podが起動したことを確認します。

kubectl get pods -w

トラフィックを生成

継続的にリクエストを送信します。

kubectl exec deployment/client -- sh -c 'while true; do curl -s server; sleep 1; done'
# 出力結果
Hostname: server-74575447bc-l9zt5
IP: 127.0.0.1
IP: ::1
IP: xx.xx.xx.xx
IP: xx.xx.xx.xx
RemoteAddr: xx.xx.xx.xx:34568
GET / HTTP/1.1
Host: server
User-Agent: curl/8.17.0
Accept: */*
...

Hubble CLIでトラフィック観測

別ターミナルでHubbleを起動します。

hubble observe --namespace default -f
# 出力結果
Dec 14 10:45:47.483: default/client-cb975b8bc-nb4kx:51944 (ID:4605) -> default/server-74575447bc-l9zt5:80 (ID:22656) to-endpoint FORWARDED (TCP Flags: SYN)
Dec 14 10:45:47.483: default/client-cb975b8bc-nb4kx:51944 (ID:4605) <- default/server-74575447bc-l9zt5:80 (ID:22656) to-endpoint FORWARDED (TCP Flags: SYN, ACK)
Dec 14 10:45:47.483: default/client-cb975b8bc-nb4kx:51944 (ID:4605) -> default/server-74575447bc-l9zt5:80 (ID:22656) to-endpoint FORWARDED (TCP Flags: ACK)
Dec 14 10:45:47.483: default/client-cb975b8bc-nb4kx:51944 (ID:4605) <> default/server-74575447bc-l9zt5 (ID:22656) pre-xlate-rev TRACED (TCP)

client → server への通信がリアルタイムで見えます!

便利なフィルタオプション

HTTP通信のみ表示

hubble observe --namespace default --protocol http -f

L7可視化を有効にする必要があります。
CiliumNetworkPolicyでL7ルールを適用すると、HTTP通信の詳細が見えるようになります。

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
  name: l7-visibility
  namespace: default
spec:
  endpointSelector:
    matchLabels:
      app: server
  ingress:
    - fromEndpoints:
        - {}
      toPorts:
        - ports:
            - port: "80"
              protocol: TCP
          rules:
            http:
              - method: "GET"
# 出力結果
Dec 14 10:51:53.966: default/client-cb975b8bc-nb4kx:54232 (ID:4605) <- default/server-74575447bc-l9zt5:80 (ID:22656) http-response FORWARDED (HTTP/1.1 200 3ms (GET http://server/))
Dec 14 10:51:54.280: default/client-cb975b8bc-nb4kx:54234 (ID:4605) -> default/server-74575447bc-l9zt5:80 (ID:22656) http-request FORWARDED (HTTP/1.1 GET http://server/)
Dec 14 10:51:54.282: default/client-cb975b8bc-nb4kx:54234 (ID:4605) <- default/server-74575447bc-l9zt5:80 (ID:22656) http-response FORWARDED (HTTP/1.1 200 3ms (GET http://server/))

DROPされた通信のみ(後続のNetworkPolicy検証で使います)

hubble observe --verdict DROPPED -f

Hubble UIで可視化

cilium hubble ui

ブラウザで http://localhost:12000 が開きます。
image.png

Hubble UIで以下のことが可能です。

  • Service Map:Pod/Service間の依存関係がグラフで見える
  • Flows:リアルタイムのトラフィックログ
  • フィルタリング:Namespace、Pod、プロトコルで絞り込み
    image.png

特にService Mapは、マイクロサービス構成の可視化に便利です。

実践:NetworkPolicyを試す

Ciliumの真価はNetworkPolicyで発揮されます。eBPFベースなので、iptablesより効率的にポリシーを適用できます。

serverへのアクセスを制限

まず、serverへの全てのIngressトラフィックを拒否するポリシーを適用します。

# deny-server-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-server-ingress
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: server
  policyTypes:
    - Ingress
kubectl apply -f deny-server-ingress.yaml

clientからアクセスしてみると、タイムアウトします。

kubectl exec deployment/client -- curl -s --max-time 5 server
# タイムアウト

CiliumNetworkPolicyとKubernetes NetworkPolicyが両方あると、CiliumNetworkPolicyが優先されます。
そのため、先ほど作成したl7-visibilityのCiliumNetworkPolicyは削除しています。

Hubbleでポリシー適用を確認

hubble observe --verdict DROPPED -f
Dec 14 11:01:38.772: default/client-cb975b8bc-nb4kx:35044 (ID:4605) <> default/server-74575447bc-l9zt5:80 (ID:22656) Policy denied DROPPED (TCP Flags: SYN)
Dec 14 11:01:40.819: default/client-cb975b8bc-nb4kx:35044 (ID:4605) <> default/server-74575447bc-l9zt5:80 (ID:22656) policy-verdict:none INGRESS DENIED (TCP Flags: SYN)

DROPPEDとして表示され、どの通信がポリシーによって拒否されたかが明確にわかります。
Hubble UIでもイベント表示を確認できます。
image.png

まとめ

今回はCilium + Hubbleをkindで試してみましたが、eBPFを意識せずともネットワーク可視化やNetworkPolicyのデバッグがここまで簡単にできるのは驚きでした。

良かった点

  1. 可視化が圧倒的に楽:Hubble UIでPod間通信がひと目でわかる
  2. NetworkPolicyのデバッグが簡単:どの通信を許可/拒否したか明確
  3. 導入のハードルが低いcilium install一発で完了
  4. kube-proxy不要:eBPFでサービスロードバランシングも実現

特にHubbleの--verdict DROPPEDは、本番環境でのトラブルシューティングでも重宝しそうです。まずはkindで感覚を掴めたので、次は検証環境での導入を検討してみたいと思います。

本番導入を考えた場合

今回はkindで試しましたが、本番環境では以下の検討が必要です。

  • カーネルバージョン:Linux 5.10以上推奨(RHEL 8.10相当)
  • 既存CNIからの移行Cilium Migration Guideを参照
  • モニタリング統合:PrometheusやGrafanaとの連携 etc

次に試してみたいこと

  • Tetragon:eBPFベースのランタイムセキュリティ
  • ClusterMesh:マルチクラスタ接続
  • Gateway API:Ciliumの次世代Ingress

この記事が少しでも誰かの参考になれば幸いです。

参考資料

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?