Leer hoe je LoadBalanced Kubernetes Services blootstelt met Cilium, met praktische stappen voor veilige, schaalbare service networking op cloud- en on-prem clusters.
Ontdek de voordelen van de BGP-integratie van Cilium, die zorgt voor efficiënte networking en sterke security zonder extra componenten.
Load balancing voor Kubernetes Services met BGP en Cilium
Cilium is een open-source project dat networking, security en observability biedt voor cloud-native omgevingen, zoals Kubernetes-clusters en andere container orchestration platforms. In deze blog laten we zien hoe je een Kubernetes Service beschikbaar maakt voor de buitenwereld met behulp van Cilium en BGP.
Hulp nodig met Cilium of Kubernetes?
Stel direct je vraag aan één van onze experts over Cilium, networking, Kubernetes, clusters of setups. We staan klaar om je te helpen!
BGP
Border Gateway Protocol (BGP) is een gestandaardiseerd exterior gateway protocol dat is ontworpen voor het uitwisselen van routing- en bereikbaarheidinformatie tussen autonome systemen (AS’en) op het internet. Het protocol wordt geclassificeerd als een path vector protocol en neemt routeringsbeslissingen op basis van paden, netwerkpolicies of regelsets die door een netwerkbeheerder zijn geconfigureerd. Omdat BGP een centrale rol speelt in kernrouteringsbeslissingen, is het cruciaal voor het functioneren van het internet.
BGP is ontwikkeld met robuustheid en schaalbaarheid als uitgangspunt en wordt gebruikt om dataverkeer te routeren tussen grote netwerken, zoals internetproviders (ISP’s) en andere grote organisaties. Het zorgt voor loop-vrije inter-domain routing en helpt een stabiele netwerkstructuur te behouden. BGP kan duizenden routes verwerken en onderscheidt zich door zijn vermogen om mee te schalen met de groei van het netwerk. Dankzij de flexibiliteit en de uitgebreide controle over routing policies wordt het breed toegepast en kan het snel reageren op veranderingen in het netwerk.
Cilium en BGP
In release 1.10 heeft Cilium BGP-ondersteuning geïntegreerd via MetalLB. Hierdoor kan Cilium Kubernetes Service IP-adressen van het type LoadBalancer via BGP aankondigen. Het resultaat is dat services vanaf buiten het Kubernetes-netwerk bereikbaar zijn, zonder extra componenten zoals een Ingress Router. Vooral dat “zonder extra componenten” is fantastisch nieuws, want elke extra component voegt latency toe — dus minder componenten betekent minder latency.
De netwerkconfiguratie die in dit voorbeeld wordt getoond, beschrijft een Kubernetes-omgeving met BGP-integratie voor service load balancing. Hieronder vind je een overzicht van de configuratie:
Client Network (LAN-netwerk(en))
Er is een local area network (LAN) met het IP-bereik 192.168.10.0/24 waarop meerdere clients zijn aangesloten. Dit netwerk vormt de gebruikerskant van de setup, waar gebruikers en andere devices toegang krijgen tot services die op het Kubernetes-cluster draaien.
Kubernetes Network
Het Kubernetes-cluster heeft een eigen netwerkruimte, aangeduid met subnet 192.168.1.0/24. Dit netwerk bevat de Kubernetes master node (k8s-master1) en meerdere worker nodes (k8s-worker1 tot en met k8s-worker5). Op deze nodes draaien de containers en workloads van het Kubernetes-cluster.
Management Network
Er is een apart managementnetwerk, met ten minste één device (k8s-control) voor het beheren en aansturen van het Kubernetes-cluster. Dit netwerk staat los van het Kubernetes dataplane, wat bijdraagt aan betere security en efficiënter beheer.
BGP Router
De bgp-router1 vormt de brug tussen het externe netwerk/de internetverbinding en het Kubernetes-netwerk. Deze router is verantwoordelijk voor het routeren van verkeer naar de juiste services binnen het Kubernetes-cluster door routes via BGP aan te kondigen. Het IP-bereik 172.16.10.0/24 is gereserveerd voor LoadBalancer services binnen het Kubernetes-cluster. Wanneer een Kubernetes Service wordt blootgesteld als LoadBalancer, krijgt deze een IP-adres uit deze pool. De BGP-router kondigt dit IP-adres vervolgens aan richting het externe netwerk, waardoor verkeer correct naar de LoadBalancer service wordt gerouteerd.
Deze netwerkconfiguratie maakt schaalbare en flexibele load balancing mogelijk voor services die op een Kubernetes-cluster draaien, door BGP te gebruiken voor IP-adresbeheer en routing. Door clienttoegang, clusterbeheer en serviceverkeer te scheiden in verschillende netwerken, ontstaat een overzichtelijke en veilige architectuur.
Een service blootstellen
Zodra de bovenstaande infrastructuur is gebouwd, is het tijd om een deployment te maken en deze via BGP aan het netwerk bloot te stellen. We beginnen met een deployment met een eenvoudige NGINX webserver die de standaard webpagina serveert. We voegen ook een Service toe met type LoadBalancer. Dit resulteert in een external IP-adres dat via BGP aan onze router wordt aangekondigd.
Zodra alles draait, laat het commando kubectl get svc zien dat onze service een external IP-adres heeft:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d3h
web1-lb LoadBalancer 10.106.236.120 172.16.10.0 80:30256/TCP 7d2h
Copy code
Het adres 172.16.10.0 ziet er misschien vreemd uit, maar dat is prima. Vaak wordt het .0-adres overgeslagen en wordt .1 als eerste adres gebruikt. Eén van de redenen is dat in de beginjaren het .0-adres werd gebruikt voor broadcast, wat later veranderde naar .255. Omdat .0 nog steeds een geldig adres is, deelt MetalLB, dat verantwoordelijk is voor de address pool, het gewoon uit als eerste adres. Het commando vtysh -c ‘show bgp summary’ op router bgp-router1 laat zien dat deze één prefix heeft ontvangen:
IPv4 Unicast Summary:
BGP router identifier 192.168.1.1, local AS number 64512 vrf-id 0
BGP table version 17
RIB entries 1, using 192 bytes of memory
Peers 6, using 128 KiB of memoryNeighbour V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt
192.168.1.10 4 64512 445 435 0 0 0 03:36:56 1 0
192.168.1.21 4 64512 446 435 0 0 0 03:36:54 1 0
192.168.1.22 4 64512 445 435 0 0 0 03:36:56 1 0
192.168.1.23 4 64512 445 435 0 0 0 03:36:56 1 0
192.168.1.24 4 64512 446 435 0 0 0 03:36:56 1 0
192.168.1.25 4 64512 445 435 0 0 0 03:36:56 1 0
Total number of neighbors 6
Copy code
Het volgende fragment uit de routing table (ip route) laat ons zien dat er voor dat specifieke IP-adres 172.16.10.0 zes mogelijke routes/bestemmingen zijn. Met andere woorden: alle Kubernetes nodes hebben aangekondigd dat ze verkeer voor dat adres afhandelen. Cool!!
172.16.10.0 proto bgp metric 20
nexthop via 192.168.1.10 dev enp7s0 weight 1
nexthop via 192.168.1.21 dev enp7s0 weight 1
nexthop via 192.168.1.22 dev enp7s0 weight 1
nexthop via 192.168.1.23 dev enp7s0 weight 1
nexthop via 192.168.1.24 dev enp7s0 weight 1
nexthop via 192.168.1.25 dev enp7s0 weight 1
Copy code
Inderdaad: de webpagina is nu zichtbaar vanaf onze router.
$ curl -s -v http://172.16.10.0/ -o /dev/null
* Trying 172.16.10.0…
* TCP_NODELAY set
* Connected to 172.16.10.0 (172.16.10.0) port 80 (#0)
> GET / HTTP/1.1
> Host: 172.16.10.0
> User-Agent: curl/7.61.1
> Accept: */*>
< HTTP/1.1 200 OK
< Server: nginx/1.21.3
< Date: Sun, 31 Oct 2023 14:19:17 GMT
< Content-Type: text/html
< Content-Length: 615
< Last-Modified: Tue, 07 Sep 2023 15:21:03 GMT
< Connection: keep-alive
< ETag: “6137835f-267”
< Accept-Ranges: bytes>
{ [615 bytes data]}
* Connection #0 to host 172.16.10.0 left intact
Copy code
En een client in ons client network kan diezelfde pagina ook bereiken, omdat die bgp-router1 als default route gebruikt.
Meer details
Nu alles werkt, willen de meeste engineers graag meer details zien — en die zal ik je niet onthouden.
Ping
Eén van de eerste dingen die je opvalt, is dat het LoadBalancer IP-adres niet bereikbaar is via ping. Als je hier dieper op ingaat, wordt duidelijk waarom. We hebben een mapping aangemaakt tussen bronpoort 80 en doelpoort 80. Deze mapping wordt uitgevoerd met eBPF-logica op de interface en is aanwezig op alle nodes. Deze mapping zorgt ervoor dat alleen verkeer voor poort 80 wordt geloadbalanced. Al het andere verkeer, inclusief ping, wordt niet opgepakt. Daarom zie je wel dat het ICMP-pakket de node bereikt, maar er nooit een response wordt verstuurd.
Verkeer observeren
Hubble is het networking- en security-observability platform dat is gebouwd bovenop eBPF en Cilium. Via zowel de command line als een grafische web-GUI is het mogelijk om huidig en historisch verkeer inzichtelijk te maken. In dit voorbeeld is Hubble geplaatst op de k8s-control node, die directe toegang heeft tot de API van Hubble Relay. Hubble Relay is de component die de benodigde informatie ophaalt bij de Cilium nodes. Let op: het hubble-commando is ook beschikbaar in elke Cilium agent pod, maar dat toont alleen informatie van die specifieke agent.
De onderstaande output laat de observatie zien die volgt uit het uitvoeren van curl http://172.16.10.0/ op de router.
$ hubble observe --namespace default --follow
Oct 31 15:43:41.382: 192.168.1.1:36946 <> default/web1-696bfbbbc4-jnxbc:80 to-overlay FORWARDED (TCP Flags: SYN)
Oct 31 15:43:41.384: 192.168.1.1:36946 <> default/web1-696bfbbbc4-jnxbc:80 to-overlay FORWARDED (TCP Flags: ACK)
Oct 31 15:43:41.384: 192.168.1.1:36946 <> default/web1-696bfbbbc4-jnxbc:80 to-overlay FORWARDED (TCP Flags: ACK, PSH)
Oct 31 15:43:41.385: 192.168.1.1:36946 <> default/web1-696bfbbbc4-jnxbc:80 to-overlay FORWARDED (TCP Flags: ACK)
Oct 31 15:43:41.385: 192.168.1.1:36946 <> default/web1-696bfbbbc4-jnxbc:80 to-overlay FORWARDED (TCP Flags: ACK)
Oct 31 15:43:41.386: 192.168.1.1:36946 <> default/web1-696bfbbbc4-jnxbc:80 to-overlay FORWARDED (TCP Flags: ACK, FIN)
Oct 31 15:43:41.386: 192.168.1.1:36946 <> default/web1-696bfbbbc4-jnxbc:80 to-overlay FORWARDED (TCP Flags: ACK)
Copy code
Eerder waarschuwde ik al om het hubble-commando niet binnen de Cilium agent pod te gebruiken, maar het kan juist ook heel waardevol zijn om het verkeer per specifieke node te bekijken. In dit geval wordt hubble observe –namespace default –follow uitgevoerd binnen elke Cilium agent pod, terwijl de curl vanaf de router één keer wordt uitgevoerd.
Op de node waar de pod daadwerkelijk draait (k8s-worker2) zien we dezelfde output als hierboven. Op een andere node (k8s-worker1) zien we echter het volgende:
Oct 31 15:56:05.220: 10.0.3.103:48278 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: SYN)
Oct 31 15:56:05.220: 10.0.3.103:48278 <- default/web1-696bfbbbc4-jnxbc:80 to-stack FORWARDED (TCP Flags: SYN, ACK)
Oct 31 15:56:05.220: 10.0.3.103:48278 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: ACK)
Oct 31 15:56:05.221: 10.0.3.103:48278 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: ACK, PSH)
Oct 31 15:56:05.221: 10.0.3.103:48278 <- default/web1-696bfbbbc4-jnxbc:80 to-stack FORWARDED (TCP Flags: ACK, PSH)
Oct 31 15:56:05.222: 10.0.3.103:48278 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: ACK, FIN)
Oct 31 15:56:05.222: 10.0.3.103:48278 <- default/web1-696bfbbbc4-jnxbc:80 to-stack FORWARDED (TCP Flags: ACK, FIN)
Oct 31 15:56:05.222: 10.0.3.103:48278 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: ACK)
Oct 31 15:56:12.739: 10.0.4.105:36956 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: SYN)
Oct 31 15:56:12.739: default/web1-696bfbbbc4-jnxbc:80 <> 10.0.4.105:36956 to-overlay FORWARDED (TCP Flags: SYN, ACK)
Oct 31 15:56:12.742: 10.0.4.105:36956 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: ACK)
Oct 31 15:56:12.742: 10.0.4.105:36956 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: ACK, PSH)
Oct 31 15:56:12.745: default/web1-696bfbbbc4-jnxbc:80 <> 10.0.4.105:36956 to-overlay FORWARDED (TCP Flags: ACK, PSH)
Oct 31 15:56:12.749: 10.0.4.105:36956 -> default/web1-696bfbbbc4-jnxbc:80 to-endpoint FORWARDED (TCP Flags: ACK, FIN)
Oct 31 15:56:12.749: default/web1-696bfbbbc4-jnxbc:80 <> 10.0.4.105:36956 to-overlay FORWARDED (TCP Flags: ACK, FIN)
Copy code
Wat we hier zien, is dat onze router het verkeer voor IP-adres 172.16.10.0 naar k8s-worker1 stuurt, maar die worker host de web1 container niet. Daarom wordt het verkeer doorgestuurd naar k8s-worker2, die het verkeer daadwerkelijk afhandelt. Alle forwarding-logica wordt afgehandeld met eBPF — een klein BPF-programma dat aan de interface is gekoppeld en het verkeer, indien nodig, doorstuurt naar een andere worker. Dat is ook de reden waarom het draaien van tcpdump op k8s-worker1, waar de pakketten initieel binnenkomen, geen verkeer laat zien. Het verkeer wordt al omgeleid naar k8s-worker2 voordat het de IP-stack van k8s-worker1 bereikt.
Ook Cilium.io biedt uitgebreide informatie over eBPF en de interne werking. Als je nog niet bekend bent met eBPF en je interesse hebt in Linux en/of networking, doe jezelf dan een plezier en leer op z’n minst de basis. Naar mijn bescheiden mening gaat eBPF networking in Linux in de nabije toekomst drastisch veranderen — en zeker binnen cloud-native omgevingen.
Hubble Web GUI
Met een werkende BGP-setup is het ook vrij eenvoudig om de Hubble Web GUI beschikbaar te maken voor de buitenwereld.
Tenslotte
Dankzij de integratie van MetalLB wordt het opzetten van Cilium met BGP opvallend eenvoudig, zonder dat dure netwerkhardware nodig is. Deze combinatie van Cilium/BGP, zeker in combinatie met het uitschakelen van kube-proxy, verlaagt de latency naar je cloud-based services aanzienlijk. Daarnaast verbetert het de security en transparantie, doordat alleen de IP-adressen van LoadBalancer services worden aangekondigd.
Hoewel deze setup geen Ingress Controller vereist, blijft er voor de meeste HTTP Services wel één aan te raden. Controllers zoals NGINX of Traefik, blootgesteld via BGP, bieden op protocolniveau grote voordelen, zoals URL rewriting en request rate limiting.
Deze vooruitgang binnen cloud-native en Linux-gebaseerde networking is echt een grote stap voorwaarts en markeert een bijzonder spannende fase in de evolutie van netwerktechnologie.
- Leer hoe je LoadBalanced Kubernetes Services blootstelt met Cilium, met praktische stappen voor veilige, schaalbare service networking op cloud- en on-prem clusters.
- Load balancing voor Kubernetes Services met BGP en Cilium
- Hulp nodig met Cilium of Kubernetes?
- BGP
- Cilium en BGP
- Een service blootstellen
- Meer details
- Hubble Web GUI
- Tenslotte
- Leer hoe je LoadBalanced Kubernetes Services blootstelt met Cilium, met praktische stappen voor veilige, schaalbare service networking op cloud- en on-prem clusters.
- Load balancing voor Kubernetes Services met BGP en Cilium
- Hulp nodig met Cilium of Kubernetes?
- BGP
- Cilium en BGP
- Een service blootstellen
- Meer details
- Hubble Web GUI
- Tenslotte