- Authors
- Name
- はじめに
- アーキテクチャとコアコンセプト
- インストールとサービスメッシュの有効化
- mTLS設定:SPIREベースの相互認証
- L4/L7トラフィック管理
- 性能比較:Cilium vs Istio vs Linkerd
- トラブルシューティング:障害事例と復旧
- 運用ノート
- 運用チェックリスト
- 参考資料

はじめに
サービスメッシュ(Service Mesh)は、マイクロサービス間の通信を安全かつ観測可能にするインフラストラクチャレイヤーです。Istio、Linkerdなどの従来のサービスメッシュソリューションは、各Podにサイドカープロキシを注入する方式を採用しています。このアプローチは機能しますが、各サイドカーが追加のCPUとメモリを消費し、Podの起動時間が長くなり、ネットワークホップの追加によりレイテンシが増加するという問題があります。
Cilium Service Meshはこのパラダイムを根本的に変革します。eBPFを活用してカーネルレベルでL4トラフィックを処理し、L7機能が必要な場合にのみノード単位の共有Envoyプロキシ(DaemonSet)を使用します。サイドカーがないためリソースオーバーヘッドが大幅に削減され、Pod単位のプロキシ管理の複雑さが解消されます。
本記事では、Cilium Service Meshのアーキテクチャ原理からインストール、mTLS設定、トラフィック管理、性能比較、そしてプロダクションで発生しうる障害事例と復旧手順までを総合的に解説します。
アーキテクチャとコアコンセプト
従来のサイドカーモデルの限界
従来のサービスメッシュでは、すべてのPodにEnvoyサイドカーが注入されます。100個のPodがあれば、100個の追加Envoyインスタンスが実行されることになります。
サイドカーモデルのコスト:
- Pod当たりEnvoyサイドカーが約50〜100MBのメモリを消費
- サイドカー初期化によるPod起動遅延(2〜5秒追加)
- すべてのトラフィックがサイドカーを経由することによる追加レイテンシ(約1ms)
- サイドカーアップグレード時に全Podのローリングリスタートが必要
Cilium Service Meshのサイドカーレスアーキテクチャ
Cilium Service Meshは2つのレイヤーでサービスメッシュ機能を実装します。
L4レイヤー(eBPF):TCP接続管理、ロードバランシング、mTLS暗号化・復号、ネットワークポリシー適用などをカーネル内のeBPFプログラムで処理します。サイドカーなしでカーネルから直接動作するため、オーバーヘッドは極めて小さくなります。
L7レイヤー(共有Envoy):HTTPルーティング、ヘッダーベースのトラフィック分割、gRPCフィルタリングなどL7機能が必要な場合にのみ、ノード当たり1つの共有Envoyプロキシ(DaemonSet)がトラフィックを処理します。Pod単位ではなくノード単位であるため、Envoyインスタンス数が大幅に削減されます。
コアコンポーネント
- Cilium Agent(DaemonSet):各ノードでeBPFプログラムをロード・管理します。サービスメッシュのデータプレーンの役割を果たします。
- Cilium Operator(Deployment):クラスタレベルのリソース管理、IPプール割り当て、CRD同期を担当します。
- Envoy DaemonSet:L7ポリシーが適用されたトラフィックのみを処理する共有プロキシです。Cilium Agentが自動的にEnvoy設定を注入します。
- Hubble:すべてのネットワークフローをリアルタイムで監視する組み込みのオブザーバビリティツールです。
インストールとサービスメッシュの有効化
前提条件
# カーネルバージョン確認(5.10以上必須、6.1以上推奨)
uname -r
# eBPFサポート確認
cat /boot/config-$(uname -r) | grep CONFIG_BPF
# CONFIG_BPF=y
# CONFIG_BPF_SYSCALL=y
# CONFIG_BPF_JIT=y
# Cilium CLIインストール
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
curl -L --fail --remote-name-all \
https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-amd64.tar.gz
sudo tar xzvf cilium-linux-amd64.tar.gz -C /usr/local/bin
Helmを使ったサービスメッシュのインストール
# Helm repoの追加
helm repo add cilium https://helm.cilium.io/
helm repo update
# Cilium Service Meshインストール(kube-proxy置換 + サービスメッシュ有効化)
helm install cilium cilium/cilium --version 1.19.0 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set k8sServiceHost="API_SERVER_IP" \
--set k8sServicePort=6443 \
--set envoyConfig.enabled=true \
--set ingressController.enabled=true \
--set ingressController.loadbalancerMode=shared \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set encryption.enabled=true \
--set encryption.type=wireguard \
--set authentication.mutual.spire.enabled=true \
--set authentication.mutual.spire.install.enabled=true
この設定の主要パラメータについて説明します:
envoyConfig.enabled=true:CiliumEnvoyConfig CRDによるL7トラフィック管理を有効化ingressController.enabled=true:CiliumをKubernetes Ingressコントローラーとして使用authentication.mutual.spire.enabled=true:SPIREベースのmTLS認証を有効化encryption.type=wireguard:WireGuardベースのノード間透過暗号化
インストールの確認
# Cilium全体ステータス確認
cilium status --wait
# 期待される出力:
# /¯¯\
# /¯¯\__/¯¯\ Cilium: OK
# \__/¯¯\__/ Operator: OK
# /¯¯\__/¯¯\ Envoy DaemonSet: OK
# \__/¯¯\__/ Hubble Relay: OK
# \__/ ClusterMesh: disabled
# SPIRE Server: OK
# SPIRE Agent: OK
# サービスメッシュ機能の確認
cilium config view | grep -E "envoy|mesh|mutual"
# 接続テスト(サービスメッシュを含む)
cilium connectivity test
mTLS設定:SPIREベースの相互認証
mTLSが必要な理由
サービスメッシュのコア機能の1つは、サービス間通信の**相互認証(mTLS)**です。mTLSはクライアントとサーバーの両方が証明書を提示して互いの身元を検証します。これにより中間者攻撃(MITM)を防止し、ネットワークポリシーとは別にワークロードアイデンティティベースのセキュリティを実現します。
CiliumはSPIFFE/SPIREフレームワークを使用してmTLSを実装します。各ワークロードにSPIFFE IDが自動的に割り当てられ、証明書の発行と更新が透過的に行われます。
mTLS認証ポリシーの適用
# mtls-authentication-policy.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: require-mutual-auth
namespace: production
spec:
endpointSelector:
matchLabels:
app: payment-service
ingress:
- fromEndpoints:
- matchLabels:
app: order-service
authentication:
mode: required # mTLS認証必須
toPorts:
- ports:
- port: '8080'
protocol: TCP
このポリシーは、payment-serviceへのインバウンドトラフィックにmTLS認証を必須とします。order-serviceが有効なSPIFFE IDを持っていない場合、接続は拒否されます。
クラスタ全体のmTLS強制
# cluster-wide-mtls.yaml
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: enforce-mtls-cluster-wide
spec:
endpointSelector:
matchExpressions:
- key: io.kubernetes.pod.namespace
operator: NotIn
values:
- kube-system
ingress:
- fromEndpoints:
- {}
authentication:
mode: required
注意事項:クラスタ全体のmTLSを有効化する前に、すべてのワークロードがSPIREに登録されていることを確認してください。未登録のワークロードは直ちに通信がブロックされます。必ずステージング環境で先にテストし、プロダクションにはネームスペースごとに段階的に適用してください。
# SPIREに登録されたワークロードの確認
kubectl exec -n kube-system spire-server-0 -- \
/opt/spire/bin/spire-server entry show
# mTLS認証ステータスの確認
cilium-dbg identity list | grep -i auth
hubble observe --namespace production --verdict DROPPED -o json | \
jq 'select(.drop_reason_desc == "Authentication required")'
L4/L7トラフィック管理
CiliumEnvoyConfigによるL7ルーティング
Cilium Service MeshはCiliumEnvoyConfig CRDを通じてL7トラフィック管理を行います。これはIstioのVirtualService/DestinationRuleと同様の役割を果たします。
# l7-traffic-split.yaml
apiVersion: cilium.io/v2
kind: CiliumEnvoyConfig
metadata:
name: api-traffic-split
namespace: production
spec:
services:
- name: api-service
namespace: production
backendServices:
- name: api-service-v1
namespace: production
- name: api-service-v2
namespace: production
resources:
- '@type': type.googleapis.com/envoy.config.listener.v3.Listener
name: api-listener
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: api-traffic
route_config:
name: api-routes
virtual_hosts:
- name: api-host
domains: ['*']
routes:
- match:
prefix: '/'
headers:
- name: 'x-canary'
exact_match: 'true'
route:
cluster: 'production/api-service-v2'
- match:
prefix: '/'
route:
weighted_clusters:
clusters:
- name: 'production/api-service-v1'
weight: 90
- name: 'production/api-service-v2'
weight: 10
http_filters:
- name: envoy.filters.http.router
typed_config:
'@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
この設定は2つのルーティングルールを定義しています:
x-canary: trueヘッダーが含まれるリクエストはv2にルーティング- 残りのリクエストはv1に90%、v2に10%の重みで分散(カナリーデプロイメント)
L4ロードバランシングポリシー
L4レベルのロードバランシングはeBPFで直接処理されるため、Envoyを経由せず非常に効率的です。
# l4-lb-policy.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: backend-l4-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend-service
ingress:
- fromEndpoints:
- matchLabels:
app: api-gateway
toPorts:
- ports:
- port: '8080'
protocol: TCP
- port: '9090'
protocol: TCP
egress:
- toEndpoints:
- matchLabels:
app: database
toPorts:
- ports:
- port: '5432'
protocol: TCP
- toEndpoints:
- matchLabels:
app: cache
toPorts:
- ports:
- port: '6379'
protocol: TCP
L7 HTTPポリシーとRate Limiting
# l7-rate-limiting.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-l7-with-ratelimit
namespace: production
spec:
endpointSelector:
matchLabels:
app: public-api
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: '8080'
protocol: TCP
rules:
http:
- method: GET
path: '/api/v1/products.*'
- method: GET
path: '/api/v1/categories.*'
- method: POST
path: '/api/v1/orders'
headers:
- 'Content-Type: application/json'
性能比較:Cilium vs Istio vs Linkerd
サービスメッシュ選定において最も重要な判断基準の1つが性能です。以下は同一ワークロード(gRPCマイクロサービス、100 RPS)で測定したベンチマーク結果です。
| 項目 | Cilium Service Mesh | Istio(サイドカー) | Linkerd |
|---|---|---|---|
| アーキテクチャ | サイドカーレス(eBPF + ノードEnvoy) | Pod単位サイドカーEnvoy | Pod単位サイドカーlinkerd2-proxy |
| P50レイテンシ追加 | 約0.1ms(L4)、約0.3ms(L7) | 約1.0ms | 約0.5ms |
| P99レイテンシ追加 | 約0.3ms(L4)、約0.8ms(L7) | 約3.0ms | 約1.5ms |
| Pod当たりメモリオーバーヘッド | 0MB(L4)/ ノード当たり約150MB共有 | 約50〜100MB | 約20〜30MB |
| Pod当たりCPUオーバーヘッド | ほぼなし(L4) | 約10〜50m | 約5〜20m |
| Pod起動遅延 | 0秒(サイドカーなし) | 2〜5秒(サイドカー注入) | 1〜3秒 |
| mTLS | SPIRE/WireGuard | 組み込み(Citadel) | 組み込み(独自PKI) |
| L7機能 | CiliumEnvoyConfig | VirtualService/DestinationRule | HTTPRoute/ServiceProfile |
| オブザーバビリティ | Hubble(組み込み) | Kiali、Jaeger(別途) | Linkerd Viz(組み込み) |
| Gateway APIサポート | ネイティブ | ネイティブ | ネイティブ |
| コミュニティ | CNCF Graduated | CNCF Graduated | CNCF Graduated |
| 学習コスト | 中程度(eBPFの理解が必要) | 高い(複雑なCRD体系) | 低い |
ベンチマークの実行方法
# fortioを使った性能測定
kubectl run fortio-client --rm -it --image=fortio/fortio -- \
load -c 50 -qps 1000 -t 60s -json - \
http://api-service.production:8080/api/v1/health
# 分析のポイント:
# - P50、P90、P99レイテンシ
# - 最大QPS(Queries Per Second)
# - エラー率
# - CPU/メモリ使用量(kubectl top podsで別途測定)
# HubbleメトリクスでL7レイテンシを確認
hubble observe --namespace production --protocol http -o json | \
jq '.l7.latency_ns / 1000000'
重要ポイント:Cilium Service MeshはL4トラフィック処理時にサイドカーモデルと比較して3〜10倍低いレイテンシを示します。L7機能を使用しても、共有Envoyモデルのおかげでpod当たりのメモリオーバーヘッドはゼロであり、ノード当たり1つのEnvoyだけでそのノードのすべてのL7トラフィックを処理します。
トラブルシューティング:障害事例と復旧
事例1:mTLS認証失敗によるサービス間通信不可
症状:特定のサービスが突然他のサービスと通信できなくなり、HubbleでAuthentication requiredドロップが観測される
# 認証失敗トラフィックの確認
hubble observe --namespace production --verdict DROPPED -o compact
# SPIREエージェントステータスの確認
kubectl get pods -n kube-system -l app=spire-agent
kubectl logs -n kube-system -l app=spire-agent --tail=50
# 特定ワークロードのSVID(証明書)ステータス確認
kubectl exec -n kube-system spire-server-0 -- \
/opt/spire/bin/spire-server entry show -selector k8s:ns:production
# Ciliumエンドポイントの認証ステータス確認
kubectl exec -n kube-system ds/cilium -- \
cilium-dbg endpoint list -o json | jq '.[].status.policy.realized.auth'
原因と解決策:
- SPIREエージェントのOOMKilled:SPIREエージェントのメモリlimitを引き上げます。大規模クラスタでは512Mi以上を推奨
- 証明書の期限切れ:SPIREのSVID TTLのデフォルトは1時間です。SPIREサーバーがダウンすると証明書が更新されず、1時間後に通信が断絶します。SPIREサーバーの高可用性を必ず確保してください
- セレクターの誤り:
CiliumNetworkPolicyのauthentication.mode: requiredが意図しない範囲に適用されている可能性があります。まず特定のネームスペースだけを対象にテストしてください
事例2:Envoy DaemonSet障害によるL7ポリシー動作不能
症状:L7 HTTPポリシー(パス・ヘッダーベースのフィルタリング)が動作せず、L4ポリシーのみが適用される
# Envoy DaemonSetステータスの確認
kubectl get ds -n kube-system cilium-envoy
kubectl describe ds -n kube-system cilium-envoy
# 特定ノードのEnvoyログ確認
kubectl logs -n kube-system -l k8s-app=cilium-envoy --tail=100
# Cilium AgentとEnvoy間の接続確認
kubectl exec -n kube-system ds/cilium -- \
cilium-dbg status --verbose | grep -A5 "Envoy"
# CiliumEnvoyConfigステータスの確認
kubectl get cec -n production -o yaml
原因と解決策:
- Envoy Podのリソース不足:ノードのL7トラフィックが多い場合、Envoyのメモリが不足する可能性があります。Helm valuesで
envoy.resources.limits.memoryを引き上げてください - 無効なCiliumEnvoyConfig:Envoy設定の文法エラーがある場合、該当リスナーがロードされません。
cilium-dbg envoy configコマンドで実際にロードされた設定を確認してください - Node Affinityの問題:特定のノードでEnvoyがスケジューリングされない場合、そのノードのL7ポリシーが動作しません
事例3:サービスメッシュアップグレード後の接続断
症状:Ciliumバージョンアップグレード後、一部のPod間通信が断続的に失敗する
# Cilium Agentローリングリスタートステータスの確認
kubectl rollout status ds/cilium -n kube-system
# eBPFマップ同期ステータスの確認
kubectl exec -n kube-system ds/cilium -- \
cilium-dbg bpf endpoint list
# エンドポイント復旧待ち
kubectl exec -n kube-system ds/cilium -- \
cilium-dbg endpoint list | grep -v ready
復旧手順:
- まず、Cilium Agentがすべてのノードで正常にリスタートされたことを確認します
- eBPFマップが正常にリロードされたかを
cilium-dbg bpf endpoint listで確認します - 問題が継続する場合、影響を受けたPodをリスタートしてエンドポイントを再登録します
- 最終手段として
cilium-dbg endpoint regenerate --allを実行し、すべてのエンドポイントのeBPFプログラムを再生成します
注意:アップグレード時は必ずhelm diff upgradeで変更内容を事前に確認し、一度に1つのマイナーバージョンずつアップグレードしてください。Cilium 1.17から1.19へのスキップはサポートされていません。
事例4:Hubble観測データが収集されない
症状:hubble observeコマンドが空の結果を返すか、タイムアウトする
# Hubble Relayステータスの確認
kubectl get pods -n kube-system -l k8s-app=hubble-relay
kubectl logs -n kube-system -l k8s-app=hubble-relay --tail=50
# Hubble接続テスト
cilium hubble port-forward &
hubble status
# Cilium AgentのHubbleモニタリングステータス
kubectl exec -n kube-system ds/cilium -- \
cilium-dbg monitor --type drop --type trace
解決策:最も一般的な原因はHubble RelayのgRPC接続の切断です。kubectl rollout restart deployment hubble-relay -n kube-systemでRelayをリスタートしてください。
運用ノート
IstioからCilium Service Meshへのマイグレーション
既存のIstio環境からCilium Service Meshへマイグレーションする場合、一括切り替えではなく段階的に進めてください。
フェーズ1 - 共存(2〜4週間):CiliumをCNIとしてインストールしますが、サービスメッシュ機能は無効のままにします。Istioサイドカーは引き続き動作します。
フェーズ2 - ネームスペースごとの切り替え:非クリティカルなネームスペースからIstioサイドカー注入を無効化し、CiliumのmTLSとL7ポリシーを有効化します。
フェーズ3 - 完全切り替え:すべてのネームスペースからIstioを削除し、Cilium Service Meshに完全移行します。
# ネームスペースごとにIstioサイドカー注入を無効化
kubectl label namespace staging istio-injection-
kubectl rollout restart deployment -n staging
# Cilium mTLSポリシーの適用
kubectl apply -f cilium-mtls-policy-staging.yaml
# 切り替え後の確認
hubble observe --namespace staging --protocol http
リソースサイジングガイドライン
Cilium Agent(DaemonSet):
- 小規模クラスタ(ノード10台以下):CPU 200m / メモリ 256Mi
- 中規模クラスタ(ノード50台以下):CPU 500m / メモリ 512Mi
- 大規模クラスタ(ノード100台以上):CPU 1000m / メモリ 1Gi
Envoy DaemonSet:
- L7トラフィックが少ない場合:CPU 100m / メモリ 128Mi
- L7トラフィックが多い場合:CPU 500m / メモリ 512Mi
- 非常に高いL7スループット:CPU 1000m / メモリ 1Gi
SPIRE Server:
- ワークロード1,000件以下:CPU 200m / メモリ 256Mi
- ワークロード5,000件以上:CPU 500m / メモリ 512Mi、HA構成が必須
必須モニタリングメトリクス
# Prometheusで収集すべき主要メトリクス
# 1. Cilium Agentステータス
# cilium_agent_api_process_time_seconds - API処理時間
# cilium_agent_bootstrap_seconds - Agent起動時間
# cilium_bpf_map_ops_total - BPFマップ操作数
# 2. サービスメッシュ関連
# cilium_proxy_upstream_reply_seconds - L7プロキシアップストリーム応答時間
# cilium_proxy_redirects - L7プロキシにリダイレクトされた接続数
# cilium_auth_map_entries - mTLS認証マップエントリ数
# 3. Hubbleオブザーバビリティ
# hubble_flows_processed_total - 処理済みフロー数
# hubble_tcp_flags_total - TCPフラグ別カウント
# Grafanaダッシュボードのインポート
# Cilium公式ダッシュボード:https://grafana.com/grafana/dashboards/16611
運用チェックリスト
デプロイ前チェックリスト
- カーネルバージョンが5.10以上であることを確認(6.1以上推奨)
CONFIG_BPF、CONFIG_BPF_SYSCALL、CONFIG_BPF_JITが有効であることを確認- kube-proxy置換モードでインストールする場合、既存のkube-proxyが削除されていることを確認
- SPIREサーバーがHA構成でデプロイされていることを確認(プロダクション必須)
CiliumNetworkPolicyが既存のKubernetesNetworkPolicyと競合しないことを確認- PodDisruptionBudgetがCilium DaemonSetとSPIREに設定されていることを確認
cilium connectivity testが成功することを確認
アップグレードチェックリスト
- Ciliumリリースノートで必ずBreaking Changesを確認
- 1つのマイナーバージョンずつ順次アップグレード(1.17 -> 1.18 -> 1.19)
helm diff upgradeで変更内容を事前確認- ステージング環境で先にアップグレードし、最低24時間観察
- アップグレード中は
cilium statusでAgentローリングリスタートをモニタリング - アップグレード後に
cilium connectivity testを再実行
障害対応チェックリスト
- Cilium Agent障害時:該当ノードのPodは既存のeBPFマップで通信を継続可能ですが、ポリシー更新は停止します
- Envoy DaemonSet障害時:L7ポリシーのみ影響を受け、L4ポリシーはeBPFで引き続き動作します
- SPIREサーバー障害時:既存証明書のTTL(デフォルト1時間)が期限切れになる前に復旧が必須です
- etcd障害時(Cilium KVStore):Cilium Agentがローカルキャッシュで動作しますが、新しいポリシーの反映はできません