BGP で Service の IP をアドバタイズする
クラウドのロードバランサーがない環境でも、Cilium は BGP を使って Service の IP を物理ネットワークに直接アナウンスできます。
クラウドプロバイダーの LoadBalancer Service タイプが機能するのは、クラウドに外部ロードバランサーをオンデマンドでプロビジョニングする API があるからです。ベアメタルなど、そのような API がない環境では、別の何かがその役割を担わない限り、LoadBalancer Service は永遠に Pending のままです。Cilium の BGP コントロールプレーンは、その役割を果たす方法の 1 つで、クラスターノードから上流ルーターに直接 BGP を話すことで、Service の IP を物理ネットワークにルーティングします。このガイドでは、これを構成する 4 つのリソースと、BGP セッションが実際に両側から確立されていることを確認する方法を説明します。
BGP が適切なツールとなるケース
クラスターノードから上流ルーターへの BGP ピアリングは、本格的なネットワーク統合です。物理(または仮想)ネットワークを管理している担当者との調整が必要で、Kubernetes 側のピア設定に一致するルーター側の設定が必要です。また、自律システムや経路アドバタイズといった BGP の概念についての実運用上の知識も必要です。クラウドの LoadBalancer と同じように、Service の IP をネットワークの他の部分から実際にルーティング可能にする必要がある、オンプレミスまたはベアメタルのクラスターに適したツールです。より単純なニーズであれば、Cilium の L2 アナウンス機能(ルーティングプロトコルを使わず、ローカルネットワークセグメント上の ARP/NDP で Service の IP をアドバタイズする)のほうが軽量な代替手段であり、クラスターが単一のネットワークセグメントにあり、セグメント間やデータセンター間のレイヤー 3 ルーティングが不要であれば、まずこちらを検討する価値があります。
4 つのリソース
4 つの CiliumBGP* カスタムリソースが連携して動作します。
CiliumLoadBalancerIPPoolは、Cilium がLoadBalancerService に割り当てられる IP アドレスの範囲を定義します。CiliumBGPAdvertisementは、BGP で何をアドバタイズするかを定義します。ここでは、そのプールから割り当てられた Service の IP です。CiliumBGPPeerConfigは、BGP をどのように話すかを定義します。タイマー、graceful restart の動作、アドレスファミリーなどです。CiliumBGPClusterConfigはこれらをまとめます。どのノードが参加するか(ラベルセレクターによる)、ローカル AS 番号、接続する上流ピア(IP と AS 番号)を指定します。
IP プールを定義する
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: apps-pool
spec:
allowFirstLastIPs: "No"
blocks:
- cidr: "10.10.211.0/24"
allowFirstLastIPs: "No" は、ネットワークアドレスとブロードキャストアドレス(.0 と .255)を割り当て可能な範囲から除外します。これは従来のサブネット割り当てから受け継がれた一般的な慣習です。CIDR は、ネットワークチームがこの目的のために実際に割り当てた範囲に合わせて調整してください。調整なしに適当に選んだプライベートレンジではなく、先方の視点から見て実際にルーティング可能なアドレス空間である必要があります。
アドバタイズする内容を定義する
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
name: bgp-advertisements
labels:
advertise: bgp
spec:
advertisements:
- advertisementType: Service
service:
addresses:
- LoadBalancerIP
selector:
matchExpressions:
- key: io.kubernetes.service.namespace
operator: Exists
これにより、一致する Service の LoadBalancerIP がアドバタイズされます。ここの labels フィールド(advertise: bgp)は、以下のピア設定が両者を結びつけるために参照するものであり、Service 自体のラベルではありません。
ピアの動作を定義する
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPPeerConfig
metadata:
name: bgp-peer-config
spec:
timers:
holdTimeSeconds: 9
keepAliveTimeSeconds: 3
gracefulRestart:
enabled: true
restartTimeSeconds: 15
families:
- afi: ipv4
safi: unicast
advertisements:
matchLabels:
advertise: bgp
ここの families.advertisements.matchLabels が、そのラベルに一致することで、このピア設定と上で定義したアドバタイズリソースを結びつけます。
すべてをまとめる:クラスター設定とノード選択
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPClusterConfig
metadata:
name: bgp-cluster-config
spec:
nodeSelector:
matchLabels:
role: bgp-node
bgpInstances:
- name: instance-1
localASN: 65011
peers:
- name: leaf-switch-1a
peerASN: 65002
peerAddress: "10.10.210.2"
peerConfigRef:
name: bgp-peer-config
- name: leaf-switch-1b
peerASN: 65002
peerAddress: "10.10.210.3"
peerConfigRef:
name: bgp-peer-config
nodeSelector は、BGP ピアリングを、クラスター内のすべてのノードが上流ルーターとピアリングしようとするのではなく、role: bgp-node というラベルの付いた意図的に選んだ一部のノードに限定します。
kubectl label node worker-4 worker-5 worker-6 role=bgp-node
妥当な範囲は 2 〜 8 ノードです。単一障害点を避けるには十分で、数十から数百ノードのクラスターのすべてのノードに対して、ネットワークチームが BGP セッションを設定して維持する必要もありません。適切な数はクラスターの物理的な配置によって異なります。複数のラックや列にまたがっている場合は、すべての BGP セッションを 1 か所に集中させるのではなく、それぞれからピアリングするのが一般的です。
4 つのリソースをすべて適用し、まず Kubernetes 側から確認します。
kubectl apply -f bgp-pool.yaml -f bgp-advertisement.yaml -f bgp-peer-config.yaml -f bgp-cluster-config.yaml
セッションが実際に確立されたことを確認する
ノードの視点から、BGP ラベルの付いたノードで動作している Cilium の Pod 内で Cilium 独自のデバッグ CLI を使います。
kubectl -n kube-system exec <cilium-pod-on-bgp-node> -- cilium-dbg bgp peers
セッション状態が established であることを確認します。それ以外の状態(idle、connect、active)は、セッションが実際には確立していないことを意味します。最も一般的な原因は、両側の AS 番号の不一致、到達できないピアアドレス、上流ルーターがまだこのピアを受け入れるように設定されていないことです。Kubernetes 側の設定が間違っていると決めつける前に、ネットワーク側のピア設定がここで宣言した内容と正確に一致しているかを確認してください。
アドレスが実際にアドバタイズされていることを確認する
プールからアドレスを取得する LoadBalancer Service を作成します。
kubectl get svc -o wide
その EXTERNAL-IP は、プールの CIDR 内のアドレスになっているはずです。上流ルーター(またはその先にあるファイアウォールやコアルーター)から、このアドレスが BGP で学習された /32 ルートとして、ピアリングしているノードのアドレスからアドバタイズされていることを確認します。その特定の /32 が現れ、それを通じて Service に正常に到達できれば、Kubernetes 側のリソースがエラーなく適用されただけでなく、IP プールの割り当て、BGP アドバタイズ、物理ネットワーク自体のルーティングがすべて正しく連携していることを、エンドツーエンドで確認できたことになります。
人気のガイド
-
Cilium が eBPF をどう使うか:アイデンティティ、ポリシー、ソケット Pod の起動、Pod 間の通信、パケットのポリシー判定のときにカーネル内で実際に何が起きているか、そしてなぜ高速なのか。 -
Cilium 用にクラスターを準備する:まずデフォルトの CNI を無効にする Cilium はクラスターのネットワーキングを完全に置き換えるため、ほとんどのアドオンよりも作業の順序が重要になります。 -
Cilium の Gateway API サポートで Service を公開する GatewayClass、Gateway、HTTPRoute:ホストベースのルーティング、パスマッチング、URL リライト、TLS。専用のゲートウェイ Pod は不要です。 -
ネットワークポリシーを書く:L3/L4 から L7 ルールまで Kubernetes はすべての Pod が他のすべての Pod に到達できる状態から始まります。CiliumNetworkPolicy はそれを絞り込む手段で、必要なら HTTP メソッドまで制限できます。