Service-IPs per BGP ankündigen
Kein Cloud-Load-Balancer? Cilium kann Service-IPs stattdessen per BGP direkt in dein physisches Netzwerk ankündigen.
Der Service-Typ LoadBalancer eines Cloud-Anbieters funktioniert, weil die Cloud eine API hat, um bei Bedarf einen externen Load Balancer bereitzustellen. Auf Bare Metal oder in jeder Umgebung ohne diese API bleibt ein LoadBalancer-Service für immer im Status Pending, solange nichts anderes diese Rolle übernimmt. Das BGP Control Plane von Cilium ist eine Möglichkeit, diese Rolle auszufüllen: Es routet die IP eines Services direkt in dein physisches Netzwerk, indem Cluster-Knoten BGP direkt mit vorgelagerten Routern sprechen. Diese Anleitung behandelt die vier Ressourcen, die das konfigurieren, und wie du von beiden Seiten prüfst, dass eine BGP-Session tatsächlich steht.
Wann BGP das richtige Werkzeug ist
BGP-Peering von Cluster-Knoten zu vorgelagerten Routern ist eine echte Netzwerkintegration. Sie erfordert Abstimmung mit den Verantwortlichen für das physische (oder virtuelle) Netzwerk, eine Router-Konfiguration auf deren Seite, die zu deiner Peer-Konfiguration auf der Kubernetes-Seite passt, und echte betriebliche Vertrautheit mit BGP-Konzepten wie Autonomen Systemen und Route Advertisement. Das ist das richtige Werkzeug für einen On-Premises- oder Bare-Metal-Cluster, dessen Service-IPs aus dem restlichen Netzwerk tatsächlich routbar sein sollen, so wie bei einem Cloud-LoadBalancer. Für einfachere Anforderungen ist Ciliums L2-Announcements-Funktion (Ankündigung der IP eines Services per ARP/NDP im lokalen Netzsegment, ohne Routingprotokoll) eine leichtgewichtigere Alternative, die du zuerst in Betracht ziehen solltest, wenn dein Cluster in einem einzelnen Netzsegment liegt und kein Layer-3-Routing zwischen Segmenten oder Rechenzentren braucht.
Die vier Ressourcen
Vier CiliumBGP*-Custom-Resources arbeiten zusammen:
CiliumLoadBalancerIPPooldefiniert einen IP-Adressbereich, den CiliumLoadBalancer-Services zuweisen kann.CiliumBGPAdvertisementdefiniert, was per BGP angekündigt wird, hier Service-IPs aus diesem Pool.CiliumBGPPeerConfigdefiniert, wie BGP gesprochen wird: Timer, Graceful-Restart-Verhalten, Adressfamilien.CiliumBGPClusterConfigverbindet alles: welche Knoten teilnehmen (über einen Label-Selector), ihre lokale AS-Nummer und mit welchen vorgelagerten Peers (per IP und AS-Nummer) sie sich verbinden.
Den IP-Pool definieren
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: apps-pool
spec:
allowFirstLastIPs: "No"
blocks:
- cidr: "10.10.211.0/24"
allowFirstLastIPs: "No" schließt die Netzwerk- und Broadcast-Adresse (.0 und .255) aus dem vergebbaren Bereich aus, eine gängige Konvention aus der klassischen Subnetz-Vergabe. Passe das CIDR an den Bereich an, den dein Netzwerkteam dafür tatsächlich bereitgestellt hat. Aus deren Sicht muss es echter, routbarer Adressraum sein und kein beliebiger privater Bereich, den du ohne Absprache gewählt hast.
Definieren, was angekündigt wird
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
Das kündigt die LoadBalancerIP passender Services an. Das Feld labels (advertise: bgp) ist das, was die Peer-Konfiguration unten referenziert, um beides zu verknüpfen – nicht ein Label an den Services selbst.
Peer-Verhalten definieren
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
Das families.advertisements.matchLabels verbindet diese Peer-Konfiguration über das Label mit der oben definierten Advertisement-Ressource.
Alles verbinden: Cluster-Konfiguration und Knotenauswahl
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 beschränkt das BGP-Peering auf eine bewusst gewählte Teilmenge von Knoten, nämlich die mit dem Label role: bgp-node, statt dass jeder Knoten im Cluster versucht, sich mit vorgelagerten Routern zu verbinden:
kubectl label node worker-4 worker-5 worker-6 role=bgp-node
Ein sinnvoller Bereich sind zwei bis acht Peering-Knoten: genug, um einen Single Point of Failure zu vermeiden, ohne dass dein Netzwerkteam BGP-Sessions gegen jeden Knoten eines Clusters mit womöglich Dutzenden oder Hunderten Knoten konfigurieren und pflegen muss. Wie viele sinnvoll sind, hängt vom physischen Aufbau deines Clusters ab. Bei Verteilung über mehrere Racks oder Reihen spricht in der Regel viel dafür, von Knoten in jedem davon aus zu peeren, statt alle BGP-Sessions an einem Ort zu bündeln.
Wende alle vier Ressourcen an und prüfe dann von der Kubernetes-Seite:
kubectl apply -f bgp-pool.yaml -f bgp-advertisement.yaml -f bgp-peer-config.yaml -f bgp-cluster-config.yaml
Prüfen, dass die Session tatsächlich steht
Aus Sicht eines Knotens, mit Ciliums eigener Debug-CLI im Cilium-Pod auf einem BGP-gelabelten Knoten:
kubectl -n kube-system exec <cilium-pod-on-bgp-node> -- cilium-dbg bgp peers
Achte auf den Session-Zustand established. Alles andere – idle, connect, active – bedeutet, dass die Session nicht zustande gekommen ist. Die häufigsten Ursachen sind eine nicht passende AS-Nummer zwischen beiden Seiten, eine nicht erreichbare Peer-Adresse oder dass der vorgelagerte Router noch gar nicht für diesen Peer konfiguriert ist. Bestätige, dass die Peer-Konfiguration auf der Netzwerkseite genau zu dem passt, was du hier deklariert hast, bevor du annimmst, dass die Konfiguration auf der Kubernetes-Seite falsch ist.
Bestätigen, dass eine Adresse tatsächlich angekündigt wird
Erstelle einen LoadBalancer-Service, der aus dem Pool zieht:
kubectl get svc -o wide
Seine EXTERNAL-IP sollte eine Adresse aus dem CIDR des Pools sein. Prüfe am vorgelagerten Router (oder an dem, was dahinter sitzt – einer Firewall oder einem Core-Router), dass diese Adresse als gelernte /32-Route per BGP erscheint, angekündigt von den Adressen der Peering-Knoten. Wenn genau diese /32 auftaucht und du den Service darüber erfolgreich erreichst, ist das die echte Ende-zu-Ende-Bestätigung, dass IP-Pool-Zuweisung, BGP-Ankündigung und das Routing des physischen Netzwerks korrekt zusammenspielen – und nicht nur, dass die Ressourcen auf der Kubernetes-Seite ohne Fehler angewendet wurden.
Beliebte Anleitungen
-
Wie Cilium eBPF nutzt: Identität, Policy und Sockets Was im Kernel tatsächlich passiert, wenn ein Pod startet, mit einem anderen Pod spricht oder eine Policy-Entscheidung für ein Paket erhält – und warum das schnell ist. -
Einen Cluster für Cilium einrichten: Zuerst das Standard-CNI deaktivieren Cilium ersetzt das Netzwerk deines Clusters vollständig, daher ist die Reihenfolge der Schritte wichtiger als bei den meisten Add-ons. -
Services mit Ciliums Gateway-API-Unterstützung bereitstellen GatewayClass, Gateway und HTTPRoute – hostbasiertes Routing, Pfad-Matching, URL-Rewrites und TLS, ohne separate Gateway-Pods. -
Network Policies schreiben: Von L3/L4- bis L7-Regeln Kubernetes startet damit, dass jeder Pod jeden anderen Pod erreichen kann – CiliumNetworkPolicy schränkt das ein, bis hinunter zur HTTP-Methode, wenn du das brauchst.