Services mit Ciliums Gateway-API-Unterstützung bereitstellen
GatewayClass, Gateway und HTTPRoute – hostbasiertes Routing, Pfad-Matching, URL-Rewrites und TLS, ohne separate Gateway-Pods.
Die Kubernetes Gateway API ist der standardisierte Nachfolger von Ingress, und Cilium implementiert sie direkt mit seinem eigenen eBPF-Datenpfad plus einem eingebetteten Envoy für die Layer-7-Verarbeitung. Diese Anleitung behandelt die Kernressourcen GatewayClass, Gateway und HTTPRoute sowie die daraus gebauten Routing-Muster. Sie setzt voraus, dass Cilium bereits mit aktivierter Gateway API installiert ist (siehe die vorherige Anleitung).
GatewayClass: Cilium als verfügbaren Controller deklarieren
Eine GatewayClass sagt dem Cluster „dieser Controller steht für Gateways zur Verfügung“:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: cilium
spec:
controllerName: io.cilium/gateway-controller
Wenn du bei der Installation gatewayAPI.gatewayClass.create: false gesetzt hast (wie es die vorherige Anleitung empfiehlt), ist das die Ressource, die du selbst erstellst, um diese Lücke zu füllen.
Die Klasse mit CiliumGatewayClassConfig anpassen
Cilium bringt mit CiliumGatewayClassConfig eine eigene CRD für Einstellungen mit, die für jedes Gateway einer bestimmten Klasse gelten sollen, meist den Kubernetes-Service-Typ, über den das Gateway bereitgestellt wird:
apiVersion: cilium.io/v2alpha1
kind: CiliumGatewayClassConfig
metadata:
name: gateway-api-config
namespace: default
spec:
service:
type: NodePort
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: cilium
spec:
controllerName: io.cilium/gateway-controller
parametersRef:
group: cilium.io
kind: CiliumGatewayClassConfig
name: gateway-api-config
namespace: default
NodePort ist hier speziell ein Zugeständnis an kind-Cluster (siehe unten). Auf einem Cluster mit einem echten Cloud-Load-Balancer ist LoadBalancer die typischere Wahl, und spätere Anleitungen dieser Reihe zur BGP-Route-Ankündigung behandeln, wie du eine routbare Adresse ganz ohne den Load Balancer eines Cloud-Anbieters bekommst.
Ein Gateway erstellen
Ein Gateway ist die eigentliche Listener-Konfiguration und referenziert die obige Klasse:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: demo-gateway
namespace: default
spec:
gatewayClassName: cilium
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
- name: https
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- name: demo-tls-secret
Keine Gateway-Pods: Hier unterscheidet sich Cilium
Bei den meisten Gateway-API-Implementierungen erzeugt ein Gateway ein dediziertes Deployment samt Pods für diese Gateway-Instanz. Bei Cilium nicht: Der Traffic wird per eBPF auf Knotenebene abgefangen und gemäß der Konfiguration des Gateways geroutet. Es erscheint nur ein Kubernetes-Service, keine Pods, die dem Gateway selbst gewidmet sind.
kubectl get gateway demo-gateway
kubectl get service -l gateway.networking.k8s.io/gateway-name=demo-gateway
Speziell auf einem kind-Cluster bekommt ein NodePort-Service standardmäßig einen zufälligen Port, nicht die Ports, die du tatsächlich willst (30080/30443 aus der früheren kind-Cluster-Konfiguration). Patche ihn explizit:
kubectl patch service <gateway-service-name> --type='json' -p='[
{"op": "replace", "path": "/spec/ports/0/nodePort", "value": 30080},
{"op": "replace", "path": "/spec/ports/1/nodePort", "value": 30443}
]'
Dieser Patch-Schritt ist rein ein kind-Workaround für das Fehlen eines echten Load Balancers und keine allgemeine Cilium-Einschränkung. Auf einem Cluster mit einer echten Cloud-LoadBalancer-Implementierung oder mit Ciliums eigenen L2-Announcements oder der BGP-Route-Ankündigung (eine spätere Anleitung dieser Reihe) bekommt der Service des Gateways eine routbare Adresse ohne manuelles Patchen.
Nach Hostname routen
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: python-route
namespace: default
spec:
parentRefs:
- name: demo-gateway
hostnames:
- "python.example.com"
rules:
- backendRefs:
- name: python-service
port: 5000
parentRefs hängt diese Route an das Gateway an (sie müssen im selben Namespace liegen, oder die Route braucht eine explizite Cross-Namespace-Referenz-Policy). Jede Anfrage mit dem Host-Header python.example.com wird an python-service geschickt.
Nach Pfad routen: Exact vs. Prefix Matching
rules:
- matches:
- path:
type: Exact
value: /
backendRefs:
- name: python-service
port: 5000
Exact passt nur auf genau diesen Pfad. Eine Anfrage an /status würde nicht auf eine Regel für / passen. Für alles jenseits eines einzelnen festen Pfads passt PathPrefix auf das angegebene Präfix und leitet den Rest des Pfads unverändert weiter:
rules:
- matches:
- path:
type: PathPrefix
value: /
Der Unterschied ist in der Praxis wichtig: Eine API mit mehreren Endpunkten hinter einer Route braucht PathPrefix, nicht Exact, sonst liefert jeder Endpunkt außerhalb des exakt passenden Pfads „Route nicht gefunden“, statt das Backend überhaupt zu erreichen.
URL-Rewrites: ein sauberer externer Pfad, ein anderer interner
Ein gängiges Muster ist, mehrere Backend-Services unter einem gemeinsamen Hostnamen mit einem aufgeräumten Pfadschema bereitzustellen, während jedes Backend seine eigenen internen Routen behält und von diesem externen Präfix nichts weiß:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: python-route
namespace: default
spec:
parentRefs:
- name: demo-gateway
hostnames:
- "example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api/python
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /
backendRefs:
- name: python-service
port: 5000
Eine Anfrage an example.com/api/python/status wird vom Präfix /api/python erfasst und vor dem Erreichen von python-service zu /status umgeschrieben, sodass das Backend selbst nie vom Präfix /api/python wissen muss, das die Außenwelt sieht. Definiere für jeden Backend-Service eine parallele Route (/api/go zu einem Go-Service und so weiter), um aus mehreren unabhängig entwickelten Backends ein einziges konsolidiertes API-Gateway zu bauen, bei dem jedes die vom Gateway extern präsentierte Pfadstruktur nicht kennt.
TLS: Zwei Dinge müssen übereinstimmen
Für HTTPS-Traffic müssen zwei Teile konsistent konfiguriert sein:
- Der HTTPS-Listener des Gateways (oben gezeigt) referenziert ein TLS-Secret und setzt
mode: Terminate. - Der
parentRefs-Eintrag jederHTTPRoute, die HTTPS-Traffic annehmen soll, muss tatsächlich den HTTPS-Listener per Namen ansprechen, nicht nur das Gateway als Ganzes:
parentRefs:
- name: demo-gateway
sectionName: https
Ohne sectionName, das auf den HTTPS-Listener zeigt, hängt sich eine Route standardmäßig an den oder die Listener, auf die ihre Match-Kriterien passen, was nicht der beabsichtigte sein muss. Erstelle das TLS-Secret, bevor du ein Gateway anwendest, das darauf verweist:
kubectl create secret tls demo-tls-secret \
--cert=path/to/cert.pem \
--key=path/to/key.pem \
-n default
kubectl describe gateway demo-gateway ist die erste Anlaufstelle, wenn ein Listener keinen Traffic wie erwartet annimmt. Ein fehlendes oder fehlerhaftes TLS-Secret ist ein häufiger Grund, warum ein Listener als nicht akzeptiert angezeigt wird.
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. -
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.