iptablesを超えて:CiliumとeBPFでKubernetesネットワーキングをスケールさせた方法

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

iptablesを超えて:Ciliumへ切り替えた理由

多くのKubernetesクラスタは、トラフィックのルーティングにiptablesIPVSを使用して開始されます。これらのツールは小規模な環境では問題なく動作しますが、10,000を超えるサービスエンドポイントが頻繁に入れ替わる環境を想定して設計されていません。私たちの本番クラスタが200ノードに達した際、顕著なCPUオーバーヘッドが発生しました。新しいPodがスケールするたびに、カーネルは何千もの連続したルールを線形探索(リニアサーチ)する必要がありました。これは非効率的であり、トラブルシューティングも困難にさせていました。

6ヶ月前、ピーク時のネットワークレイテンシが15〜20msほど上昇し始めました。同時に、セキュリティチームからは、標準的なログでは提供できないPod間通信の詳細な可視化を求められました。そこで私たちは、Ciliumへの移行を決定しました。従来のCNIとは異なり、CiliumはeBPF (Extended Berkeley Packet Filter)を活用します。これにより、低速なiptablesスタックを完全にバイパスし、Linuxカーネル内でサンドボックス化されたプログラムを直接実行できるようになります。

本番環境での結果は非常に安定しています。eBPFベースのCNIへの移行は、セキュリティとモニタリングの扱いを根本から変えました。このガイドでは、Ciliumをデプロイするための実践的な手順と、なぜそれが現代のインフラにとって戦略的な選択肢となるのかを説明します。

ステップ1:環境の準備とインストール

最高のパフォーマンスを得るには、既存のCNIがないクラスタにCiliumをデプロイすることをお勧めします。EKSやGKEなどのマネージドサービスを使用している場合は、クラスタ作成時にデフォルトのプロバイダーを無効にできることがよくあります。最初の検証には、Cilium CLIを使用することをお勧めします。

まず、バイナリを取得してインストールします。このツールは、ノードがeBPFと互換性があるかを確認するための事前チェック(pre-flight checks)を実行します。

CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all "https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}"
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}

実際のデプロイにはHelmを使用するのが好みです。GitOpsパイプラインとの統合が容易で、バージョンの固定も簡単だからです。ここでは、最新のパフォーマンスパッチを利用するためにバージョン1.16.0を使用します。

helm repo add cilium https://helm.cilium.io/

helm install cilium cilium/cilium --version 1.16.0 \
  --namespace kube-system \
  --set hubble.enabled=true \
  --set hubble.relay.enabled=true \
  --set hubble.ui.enabled=true \
  --set prometheus.enabled=true \
  --set operator.prometheus.enabled=true \
  --set kubeProxyReplacement=true

kubeProxyReplacement=trueの設定は重要なステップです。これにより、CiliumがLoadBalancerやNodePortサービスを直接処理するようになり、kube-proxyが不要になります。Podが起動したら、メッシュの状態を確認してください。

cilium status --wait

ステップ2:きめ細かなセキュリティのためのL7ポリシーの実装

標準のKubernetes NetworkPolicyは、大まかな制御しかできません。これらはレイヤー3および4で動作するため、IPやポートのブロックしか行えません。例えば、Podがapi.github.comにアクセスするのを許可しつつ、他の外部トラフィックをブロックしたい場合、GitHubのIPアドレスは頻繁に変わるため、標準的なポリシーでは対応できません。

Ciliumは、FQDN対応ポリシーレイヤー7 (HTTP) フィルタリングを提供します。私たちの構成では、フロントエンドが特定のAPIパスに対してのみGETリクエストを実行できるように制限しました。これにより、Podが侵害された場合でも横方向の移動(ラテラルムーブメント)を防ぐことができます。

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "restrict-api-access"
  namespace: production
spec:
  endpointSelector:
    matchLabels:
      app: backend-service
  ingress:
  - fromEndpoints:
    - matchLabels:
        app: frontend-web
    toPorts:
    - ports:
      - port: "8080"
        protocol: TCP
      rules:
        http:
        - method: "GET"
          path: "/api/v1/public/.*"

このレベルの制御は極めて重要です。攻撃者が悪意のあるデータをPOSTしようとしたり、/adminエンドポイントにアクセスしようとしたりしても、カーネルが即座にパケットを破棄します。eBPFがデータプレーンでこのフィルタリングを処理するため、リクエストのレイテンシに測定可能な増加は見られませんでした。

ステップ3:Hubbleによるリアルタイム・オブザーバビリティ

Ciliumの最も具体的なメリットはHubbleです。分散システムで「Connection Refused」エラーをデバッグするには、通常tcpdumpと多大な忍耐が必要です。Hubbleは、クラスタ内のすべてのフローをハイレベルなストリームとして提供することで、その状況を一変させます。

ターミナルからトラフィックをライブで監視し、どのポリシーがパケットをドロップしているかを正確に把握できます。

cilium hubble port-forward &
hubble observe --namespace production --follow --outcome dropped

GUIを好む場合は、Hubble UIが動的なサービスマップを生成してくれます。実際のトラフィックに基づいて、マイクロサービス間の依存関係を自動的に描画します。これは私たちのチームにとって大きな収穫でした。これを使用して、データベースに対して未承認の呼び出しを行っていたいくつかのレガシーサービスを特定することができました。ダッシュボードを起動するには、次のコマンドを実行するだけです。

cilium hubble ui

localhost:12000にアクセスすると、クラスタの状態が視覚的に表示されます。ブロックされたトラフィックを表す「赤い線」を見ることで、セキュリティポリシーが意図通りに機能していることを即座に確認できます。

本番環境での6ヶ月間から得られた教訓

Ciliumの運用は簡単ですが、ノードのリソースに関する考え方を切り替える必要があります。私たちの経験から得られた3つの重要なポイントを以下に示します。

  • カーネルをアップグレードする: Ciliumは古いバージョンもサポートしていますが、実際には Linux 5.10以降が必要です。私たちは最も効率的なeBPFヘルパーを使用するために5.15に移行し、これによりノードのCPU使用率をさらに5%削減できました。
  • メモリ使用量を監視する: CiliumエージェントはFlannelよりもリソースを消費します。特にフローの並行性が高く、Hubbleが有効な場合は、ノードあたり約200MBから500MBのRAMを割り当てることを想定してください。
  • kube-proxyを廃止する: 両方を実行しないでください。Ciliumを完全な代替モード(full replacement mode)で使用することで、ネットワークスタックが簡素化され、大規模なiptablesルールセットを管理する複雑さが解消されます。

Ciliumは単なるCNIではありません。カーネルに組み込まれたセキュリティおよびオブザーバビリティのプラットフォームです. Kubernetes環境をスケールさせるなら、eBPFこそが最もパフォーマンスの高い進むべき道です。

Share: