Kubernetes Networking: CNI, Cilium met eBPF en netwerkbeleid
Kubernetes abstraheert het netwerk op meesterlijke wijze: elke Pod krijgt een routeerbaar IP-adres, containers binnen dezelfde Pod delen de netwerknaamruimte, en Pods kunnen dat ook met elkaar communiceren op elk knooppunt zonder NAT. Toch gaat de schijnbare eenvoud schuil een echte complexiteit: hoe werkt dit model eigenlijk? Met wie wordt omgegaan IP's toewijzen, verkeer tussen knooppunten routeren, netwerkbeleid implementeren?
Het antwoord ligt in Containernetwerkinterface (CNI), een standaard die definieert hoe netwerkplug-ins moeten worden geïntegreerd met Kubernetes. In dit artikel we zullen het Kubernetes-netwerkmodel van binnenuit verkennen: hoe kube-proxy werkt, waarom Cilium met eBPF vervangt het traditionele oplossingen, en hoe? Implementeer netwerkbeleid om werklasten in productieclusters te isoleren.
Wat je gaat leren
- Het Kubernetes-netwerkmodel: IP-per-Pod, plat netwerk, geen NAT
- Hoe de Container Network Interface (CNI) werkt en de belangrijkste plug-ins
- Het verschil tussen kube-proxy (iptables/IPVS) en Cilium met eBPF
- Omdat eBPF -30% latentie en +60% doorvoer biedt vergeleken met iptables
- Hoe Cilium als CNI te installeren en configureren
- Netwerkbeleid: syntaxis, praktische voorbeelden, standaard-deny en naamruimte-isolatie
- CiliumNetworkPolicy voor Layer 7-regels (HTTP, gRPC, Kafka)
Het Kubernetes-netwerkmodel
Kubernetes legt een netwerkmodel op met vier fundamentele vereisten De CNI-implementatie moet voldoen aan:
- Alle Pods kunnen zonder NAT communiceren met alle andere Pods
- Alle knooppunten kunnen zonder NAT met alle pods communiceren
- Het IP-adres dat een Pod als zijn eigen IP-adres beschouwt en hetzelfde IP-adres dat anderen gebruiken om deze te bereiken
- Containers binnen een Pod delen netwerknaamruimten en IP-adressen
Dit "platte netwerkmodel" vereenvoudigt het redeneren van toepassingen aanzienlijk: microservice hoeft niet te weten of de dienst die wordt aangeroepen zich op hetzelfde knooppunt of op een knooppunt bevindt afgelegen. De complexiteit wordt verplaatst naar de clusternetwerklaag.
Hoe de communicatie tussen pods werkt
Wanneer een Pod A wil communiceren met een Pod B op verschillende knooppunten, is de typische stroom de gevolgd door een oplossing op basis van een overlay-netwerk (bijvoorbeeld VXLAN):
- Het pakket verlaat de container van Pod A via de interface
eth0 - Voer de knooppuntnaamruimte in via a
veth pair - De CNI-plug-in onderschept het en kapselt het in VXLAN (of GRE, Geneve...)
- Het pakket doorkruist het fysieke netwerk naar het Pod B-knooppunt
- De CNI op het bestemmingsknooppunt ontkapselt het pakket
- Het pakket arriveert bij Pod B via zijn veth-paar
Met oplossingen gebaseerd op BGP of native routing (zoals Cilium in native routing-modus), inkapseling is niet nodig en de prestaties verbeteren aanzienlijk.
Containernetwerkinterface (CNI)
De CNI is een CNCF-specificatie die definieert hoe containerruntimes moeten worden aangeroepen netwerk plug-ins. Kubernetes gebruikt CNI om netwerkbeheer te delegeren aan plug-ins: wanneer de kubelet een pod maakt, roept deze de geconfigureerde CNI-plug-in aan om het adres toe te wijzen IP en configureer de netwerkinterface.
Belangrijkste CNI-plug-ins
| Plug-ins | Technologie | Netwerkbeleid | L7-beleid | Gebruikscasus |
|---|---|---|---|---|
| Flanel | VXLAN-overlay | Nee (native) | No | Ontwikkeling, eenvoudige clusters |
| Calico | BGP/overlay | Si | No | Op locatie, prestaties |
| Cilium | eBPF | Si | Ja (HTTP, gRPC) | Productie, servicegaas |
| AWS VPC CNI | ENI geboren | Ja (SG) | No | EKS |
| Azure-CNI | Systeemeigen VNet | Ja (NSG) | No | AKS |
kube-proxy: de oude aanpak
kube-proxy is de Kubernetes-component die verantwoordelijk is voor de implementatie van de Services: wanneer een client een Service aanroept, zorgt kube-proxy ervoor dat het verkeer bij een van de Pod-backend. Traditioneel gebruikt iptables voor dit doel.
Het probleem met iptables is dat de complexiteit lineair schaalt met het aantal regels. In een cluster met 10.000 Services en 100.000 endpoints beheert iptables miljoenen regels. Elk pakket moet deze reeks regels doorlopen, met aanzienlijke impact op de latentie en CPU van het knooppunt.
Het in-tree alternatief e IPVS (IP Virtual Server), die een hashtabel gebruikt voor O(1) opzoeken in plaats van iptables lineaire scan. Maar IPVS heeft ook beperkingen: Het ondersteunt geen geavanceerd beleid en vereist nog steeds het beheer van aanvullende iptables-regels.
iptables schaalprobleem
Met 10.000 services creëert kube-proxy met iptables alleen al voor services ongeveer 40.000 regels. De updatetijd van deze regels groeit van milliseconden naar minuten. Geclusterd groot is, leidt dit tot hoge latenties tijdens schaalgebeurtenissen en implementatie-updates. Dit is een van de belangrijkste redenen waarom Cilium kube-proxy vervangt.
Cilium en eBPF: de toekomst van Kubernetes-netwerken
eBPF (extended Berkeley Packet Filter) is een Linux-kerneltechnologie waarmee je programma's in de sandbox rechtstreeks in de kernel kunt uitvoeren, zonder deze te wijzigen, bijvoorbeeld zonder kernelmodules. Cilium gebruikt eBPF om netwerkverkeer te onderscheppen en te verwerken op kernelniveau, waarbij iptables en kube-proxy volledig worden omzeild.
Voordelen van Cilium met eBPF
- Prestatie: Latency tot 30% verminderd, doorvoer met 60% verhoogd vergeleken met iptables
- Schaalbaarheid: O(1) opzoeken met BPF-kaarten in plaats van lineaire scan met iptables
- Waarneembaarheid: Hubble biedt realtime inzicht in L3/L4/L7-verkeer
- Laag 7-beleid: Beleid gebaseerd op HTTP-pad, methode, header, gRPC-methode, Kafka-onderwerp
- Service Mesh zonder zijspan: mTLS en load-balancing geïmplementeerd in de kernel, geen zijspan-overhead
- Vervanging van Kube-proxy: Cilium kan kube-proxy volledig vervangen
Cilium-installatie
We installeren Cilium op een Kubernetes-cluster met behulp van Helm en configureren het om te vervangen kube-proxy en schakel Hubble in voor observatie:
# Aggiungi il repo Helm di Cilium
helm repo add cilium https://helm.cilium.io/
helm repo update
# Installa Cilium con kube-proxy replacement e Hubble abilitati
helm install cilium cilium/cilium \
--version 1.16.0 \
--namespace kube-system \
--set kubeProxyReplacement=true \
--set k8sServiceHost=API_SERVER_HOST \
--set k8sServicePort=API_SERVER_PORT \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set ipam.mode=kubernetes
# Verifica installazione
cilium status --wait
# Verifica connettivita
cilium connectivity test
Cilium in productie: geavanceerde configuratie
Voor een productiecluster vindt u hier een volledige Helm-waardenconfiguratie met native routing (zonder VXLAN-inkapseling) om de prestaties te maximaliseren:
# cilium-values-production.yaml
kubeProxyReplacement: true
k8sServiceHost: "10.0.0.1" # indirizzo API server
k8sServicePort: "6443"
# Native routing mode (senza overlay VXLAN)
# Richiede che la rete sottostante supporti il routing dei pod CIDR
tunnel: disabled
autoDirectNodeRoutes: true
ipv4NativeRoutingCIDR: "10.244.0.0/16"
# IPAM
ipam:
mode: kubernetes
# BGP per annunciare i pod CIDR ai router
bgp:
enabled: true
announce:
podCIDR: true
lbIP: true
# Hubble - osservabilita Layer 7
hubble:
enabled: true
metrics:
enabled:
- dns:query;ignoreAAAA
- drop
- tcp
- flow
- icmp
- http
relay:
enabled: true
replicas: 2
ui:
enabled: true
# Monitoring con Prometheus
prometheus:
enabled: true
serviceMonitor:
enabled: true
# Encryption (WireGuard)
encryption:
enabled: true
type: wireguard
# Load Balancing con DSR (Direct Server Return)
loadBalancer:
mode: dsr # elimina un hop di rete nel path di ritorno
# Limita connessioni per Pod
bpf:
mapDynamicSizeRatio: 0.0025
Netwerkbeleid in Kubernetes
Standaard kunnen alle Pods in een Kubernetes-cluster vrij met elkaar communiceren. Dit is handig voor de ontwikkeling, maar is een beveiligingsprobleem bij de productie. De Netwerkbeleid kunt u in- en uitgangsregels voor pods definiëren.
Let op: CNI-plug-in vereist
NetworkPolicies zijn een Kubernetes-bron, maar de implementatie ervan is afhankelijk van de CNI-plug-ins. Flanel ondersteunt NetworkPolicy niet standaard. Om ze te gebruiken heb je Cilium nodig, Calico, of een andere CNI die ze implementeert. De bron wordt geaccepteerd door de server-API maar genegeerd als de CNI het niet ondersteunt.
Standaard weigeren: de fundamentele best practice
De eerste stap om workloads te isoleren en beleid toe te passen standaard-weigeren op elke naamruimte. Hiermee wordt al het verkeer geweigerd dat niet expliciet is toegestaan:
# default-deny-all.yaml
# Nega tutto il traffico ingress e egress nel namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
podSelector: {} # seleziona TUTTI i pod nel namespace
policyTypes:
- Ingress
- Egress
---
# Permetti il traffico DNS (necessario per la risoluzione dei nomi)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
Netwerkbeleid voor een typische toepassing
Laten we eens kijken hoe we een applicatie met drie niveaus kunnen isoleren: frontend, backend, database. Alleen de frontend accepteert verkeer van buitenaf, alleen de backend kan de DB bereiken:
# network-policies-app.yaml
# Frontend: accetta traffico dall'ingress controller
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-ingress-to-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: frontend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ingress-nginx
podSelector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 8000
- ports:
- protocol: UDP
port: 53
---
# Backend: accetta solo dal frontend, puo raggiungere DB
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8000
egress:
- to:
- podSelector:
matchLabels:
app: database
ports:
- protocol: TCP
port: 5432
- ports:
- protocol: UDP
port: 53
---
# Database: accetta solo dal backend
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-backend-to-database
namespace: production
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: backend
ports:
- protocol: TCP
port: 5432
CiliumNetworkPolicy: Beleidslaag 7
Standaard Kubernetes NetworkPolicies werken op Layer 3/4 (IP en poort). Cilium strekt zich uit dit met CiliumNetwerkbeleid, dat op inhoud gebaseerd beleid mogelijk maakt van communicatie: HTTP-pad, gRPC-methode, Kafka-onderwerp, DNS-query.
HTTP-beleid met Cilium
We staan toe dat de frontend alleen specifieke backend-eindpunten aanroept:
# cilium-http-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: frontend-to-backend-l7
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8000"
protocol: TCP
rules:
http:
- method: "GET"
path: "/api/v1/products.*"
- method: "POST"
path: "/api/v1/orders"
- method: "GET"
path: "/health"
DNS-beleid met Cilium
Beperk de DNS-domeinen die een Pod kan omzetten (handig om gegevensexfiltratie te voorkomen):
# cilium-dns-policy.yaml
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: restrict-dns-egress
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend
egress:
# Permetti solo DNS verso il cluster DNS
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s:k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*.internal.company.com"
- matchPattern: "*.svc.cluster.local"
- matchPattern: "api.stripe.com"
Hubble: Netwerkwaarneembaarheid
Hubble en de Cilium-waarneembaarheidslaag. Biedt real-time zichtbaarheid op al het clusternetwerkverkeer, met communicatie-identiteiten gebaseerd op Kubernetes-labels in plaats van IP-adressen.
# Installa il CLI di Hubble
export HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
curl -L --fail --remote-name-all \
https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-amd64.tar.gz
tar xzvf hubble-linux-amd64.tar.gz
sudo mv hubble /usr/local/bin
# Port-forward al relay Hubble
cilium hubble port-forward &
# Osserva il traffico in tempo reale
hubble observe --namespace production --follow
# Filtra per Pod specifici
hubble observe \
--namespace production \
--from-pod frontend-7d9d6b8f-abc12 \
--to-pod backend-5c4f8d9-xyz99 \
--follow
# Mostra solo i drop (traffico bloccato dalle policy)
hubble observe \
--namespace production \
--verdict DROPPED \
--follow
# Statistiche per service
hubble observe \
--namespace production \
--output json | jq '.flow.destination.namespace'
Foutopsporing en probleemoplossing voor netwerkbeleid
Foutopsporing in NetworkPolicies is een van de meest voorkomende uitdagingen in Kubernetes. Hier is één benadering systematisch:
# 1. Verifica quali NetworkPolicy si applicano a un Pod
kubectl get networkpolicies -n production -o wide
# 2. Test di connettivita con un Pod temporaneo
kubectl run test-pod \
--image=nicolaka/netshoot \
--rm \
-it \
--restart=Never \
-n production \
-- bash
# All'interno del Pod:
# Test TCP
nc -zv backend-service 8000
# Test DNS
nslookup backend-service.production.svc.cluster.local
# Test HTTP
curl -v http://backend-service:8000/health
# 3. Con Cilium, usa il tool di policy verification
cilium policy get # mostra tutte le policy caricate
# 4. Testa la connettivita specifica
kubectl exec -n production frontend-pod -- \
curl -v http://backend-service:8000/api/v1/products
# 5. Con Hubble, vedi perche un pacchetto viene droppato
hubble observe \
--namespace production \
--verdict DROPPED \
--from-pod frontend-7d9d6b8f \
--follow
Isolatie van meerdere naamruimten
In clusters met meerdere tenants is het van cruciaal belang om naamruimten te isoleren. Standaard is dit Netwerkbeleid ze blokkeren het verkeer tussen de verschillende naamruimten niet. Zo implementeert u volledige isolatie:
# Isola completamente un namespace da tutti gli altri
# (ma permette il traffico interno al namespace)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: namespace-isolation
namespace: tenant-a
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
# Permetti solo traffico dallo stesso namespace
- from:
- podSelector: {}
# Permetti da monitoring namespace
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
egress:
# Permetti solo traffico verso lo stesso namespace
- to:
- podSelector: {}
# Permetti DNS
- ports:
- protocol: UDP
port: 53
# Permetti verso monitoring namespace
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
Prestatiebenchmark: Cilium versus Kube-proxy
Benchmarks laten significante verschillen zien tussen Cilium met eBPF en kube-proxy met iptables in clusters met een groot aantal Services:
| Metrisch | kube-proxy iptables | Cilium eBPF | Verbetering |
|---|---|---|---|
| P50-latentie (10K svc) | 450 µs | 130 µs | -71% |
| P99-latentie (10K svc) | 2,1 ms | 320 µs | -85% |
| Doorvoer (Gbps) | 22Gbps | 36Gbps | +64% |
| CPU-updateregels (10K svc) | 180 sec | 2 sec | -99% |
| Verbindingen/sec | 220K | 380K | +73% |
Best practices voor Kubernetes-netwerken
Controlelijst voor productienetwerken
- Kies nu de juiste CNI: Migare CNI in productie en complex. Overweeg Cilium als u van plan bent geavanceerd netwerkbeleid of service mesh te gebruiken
- Standaard-deny in elke naamruimte: Begin altijd met een 'alles weigeren'-beleid en voeg vervolgens uitzonderingen toe
- Consistente labels op Pods: NetworkPolicies zijn afhankelijk van labels; gebruik duidelijke conventies (app, laag, versie)
- Test beleid voordat u het implementeert: VS
cilium connectivity testof testpods om te controleren - Hubble inschakelen: In de productie is verkeerszichtbaarheid van cruciaal belang voor foutopsporing en compliance
- Trackdrops: Configureer waarschuwingen op Prometheus voor onverwacht weggevallen verkeer
- Blokkeer DNS niet: Vergeet niet om UDP/TCP 53 toe te staan aan kube-dns in uw uitgaand beleid
- Documentbeleid: Gebruik Kubernetes-annotaties om het doel van elk netwerkbeleid te beschrijven
Antipatronen die u moet vermijden
Veelvoorkomende fouten met netwerkbeleid
- Te laks beleid: Gebruik
namespaceSelector: {}zonder matchLabels staat verkeer van ALLE naamruimten toe, inclusief gecompromitteerde naamruimten - DNS vergeten: Als u al het uitgaande verkeer blokkeert en poort 53 vergeet, zullen uw Pods geen hostnamen meer omzetten
- Etiketten niet bijgewerkt: Als u nieuwe Pods toevoegt zonder de juiste labels, beschermt NetworkPolicies deze niet
- Alleen tests in ontwikkeling: NetworkPolicies kunnen onverwacht verkeer in de productie blokkeren. Test altijd in enscenering met realistisch verkeer
- Gebruik IP in plaats van selectors: Pod-IP's veranderen; gebruik altijd podSelector en namespaceSelector, nooit ipBlock voor intern verkeer
Conclusies en volgende stappen
Het Kubernetes-netwerkmodel, met zijn platte, IP-per-Pod-aanpak, is elegant van ontwerp zijn eenvoud en toch verfijnd in de implementatie. Het kiezen van de CNI-plug-in is een van de belangrijkste architecturale beslissingen voor een productiecluster: beïnvloed de prestatie-, beveiligings- en observatiefuncties beschikbaar.
Cilium met eBPF is de meest geavanceerde CNI die momenteel beschikbaar is: vervang kube-proxy door superieure prestaties, biedt Layer 7-beleid, integreert observatie met Hubble en kan een traditioneel servicegaas voor mTLS vervangen. Voor nieuwe clusters in productie, en de keuze die wordt aanbevolen door de CNCF-gemeenschap en grote spelers zoals Google, Amazon en Microsoft die het gebruikt in hun beheerde Kubernetes-services.
Netwerkbeleid dat correct wordt geïmplementeerd met een ‘default-deny’-benadering, vermindert het netwerkverkeer het aanvalsoppervlak drastisch als een Pod wordt aangetast. Ik niet optioneel bij de productie: ze vormen een fundamentele veiligheidsvereiste.
Aankomende artikelen in de Kubernetes at Scale-serie
Gerelateerde serie
- MLOps en machine learning in productie — GPU-workloads op Kubernetes
- Platformtechniek - Interne ontwikkelaarsplatforms op K8s
- Waarneembaarheid en OpenTelemetrie — clustermonitoring







