Van Ingress naar Gateway API zonder big-bang
Probleemstelling in 60 seconden
In multi-team clusters loopt “classic” Ingress vaak stuk op drie heel praktische dingen: extensibility via annotations, portability en ownership.
Ingress is bewust klein gehouden: het dekt vooral TLS termination en simpele host/path routing, en alles daarbuiten komt in de praktijk neer op controller-specifieke extensies (meestal annotations). Zie de Ingress-documentatie en de Gateway API migratiegids. Kubernetes raadt Gateway aan boven Ingress, en de Ingress API is “frozen” (wel GA/stable, maar geen verdere feature-ontwikkeling). “Frozen” betekent hier niet “deprecated” of “wordt verwijderd”, maar “stabiel contract”.
Wat je dan ziet in het wild (en wat je als platform-team mag oplossen):
- Annotations-hell / fragmentatie: elke controller heeft zijn eigen key-value strings, vaak met semantiek die niet in de API zelf zit.
- Ownership-issues: één Ingress object mengt infra-keuzes (entrypoints, TLS, LB specifics) met app-routing. In een gedeelde cluster betekent dat vaak: óf iedereen “kan alles”, óf teams moeten tickets schieten voor elke wijziging.
- Vendor/controller lock-in: als je afhankelijk wordt van controller-specifieke annotations, wordt wisselen duur/risicovol.
Wanneer Ingress nog prima is (en dat mag je rustig hardop zeggen):
- Je hebt één team dat de controller én alle Ingress resources beheert (self-service is niet het probleem).
- Je routing is simpel (host/path + TLS) en je gebruikt weinig tot geen controller-extensies. Dat is precies het feature-gebied waarvoor Ingress bedoeld is.
- Je wilt (voor nu) bewust niet investeren in een nieuw governance-model en je hebt geen multi-tenant druk.
Realiteit check (feb 2026): als je community ingress-nginx draait, is er een harde lifecycle-driver. Kubernetes SIG Network + SRC hebben retirement aangekondigd in deze aankondiging en later verduidelijkt in een statement/statusupdate. Dat is niet “Ingress verdwijnt”, maar wel: een internet-facing component zonder security updates is een governance- en risk-discussie die je niet wint met “we laten het nog even staan”. Check daarom altijd de actuele status en release notes voordat je productiekeuzes vastzet.
Gateway API: het minimum dat je moet snappen
De kern is niet “meer features”, maar roles + duidelijke contracten. Kubernetes noemt dat expliciet als design principle: role‑oriented (infra provider / cluster operator / app developer), portable, expressive en extensible. Ook: veel dingen die bij Ingress alleen via annotations konden, zitten nu structureel in de API.
In de praktijk raak je (voor HTTP) vooral deze vier objecten:
- GatewayClass: cluster-scoped “welke controller beheert dit?”, vergelijkbaar met IngressClass/StorageClass; je hebt er minimaal één nodig.
- Gateway: de “entrypoint”/infra-instance (listeners: protocol/port/hostname/TLS), vaak owned door platform of cluster operators.
- HTTPRoute: app-level routing rules (host/path/header/query matches, filters, backends).
- ReferenceGrant: expliciete handshake voor cross-namespace references (bijv. Route → Service in andere namespace, of Gateway → Secret in andere namespace). Zonder grant is de reference ongeldig; dit is bewust een security-safeguard.
Status conditions & events veranderen je debugging
Gateway API leunt zwaar op status conditions zodat je sneller kunt zien waarom iets niet werkt: is het object geaccepteerd door de controller, konden referenties worden resolved, is de dataplane geprogrammeerd?
De SIG Network GEP over status/conditions (GEP-1364) legt uit dat Gateway API conditions positief gepolariseerd zijn voor “happy state”: Accepted, ResolvedRefs, en Programmed (en Ready als Extended). Error-conditions zijn negatief gepolariseerd en verschijnen als ze “True” zijn.
De exacte set conditions kan per controller en feature-level afwijken, maar Accepted, ResolvedRefs en Programmed zie je in de praktijk vrijwel overal terug.
Praktisch verschil met Ingress-debugging: je zit minder in “controller logs + gokken” en meer in “kubectl get/describe + status.parents + events”, en pas daarna duik je de controller in.
Hands-on lab: Gateway API in kind
Doel: in <30 minuten een draaiend lab met host-based, path-based routing én weighted traffic split (canary). Dit is copy/paste, laptop-proof.
Vereisten
- Docker
- kind
- kubectl
- Helm 3
- curl
(Je hoeft geen LoadBalancer in kind te hebben: we testen via kubectl port-forward, net als in de Envoy Gateway quickstart.)
Controller-keuze: waarom Envoy Gateway voor dit lab?
Voor een lab wil je drie dingen: snelle installatie, duidelijke docs, ondersteuning van standard features zoals weighted backendRefs.
- Envoy Gateway: quickstart is 1 Helm install + port-forward flow, en heeft expliciete docs voor HTTP routing en traffic splitting met
weightop backendRefs. - Alternatieven (ook prima, maar andere install ergonomics):
- NGINX Gateway Fabric heeft een kind-get-started met NodePort mappings in kind config + Helm install.
- Project Contour kan Gateway API via static of dynamic provisioning; prima, maar net wat meer moving parts in een “quick demo”.
Controller-specifiek vs generiek:
- Generiek (spec): GatewayClass/Gateway/HTTPRoute/ReferenceGrant semantics,
allowedRoutes, matching rules,weight, en status conditions (Accepted/ResolvedRefs/Programmed). - Controller-specifiek: hoe de dataplane wordt uitgerold (Deployment/DaemonSet), hoe je een “address” krijgt in kind (LB/NodePort/port-forward), welke extra Policy CRDs bestaan, en welke conformance (Core/Extended/Implementation-specific) features precies ondersteund zijn.
Stap-voor-stap
kind cluster aanmaken
kind create cluster --name gwapi-lab
kubectl cluster-info --context kind-gwapi-lab
Envoy Gateway installeren
Volgens de quickstart installeer je tegelijk de Gateway API CRDs + Envoy Gateway via Helm, en wacht je tot de deployment Available is.
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.7.0 \
-n envoy-gateway-system --create-namespace
kubectl wait --timeout=5m -n envoy-gateway-system deployment/envoy-gateway --for=condition=Available
Expected output (indicatief):
kubectl -n envoy-gateway-system get deploy,po
Je wilt 1 deployment Available en pods Running.
Namespaces + sample app (2 services)
We maken een infra-namespace voor de Gateway en een app-namespace met twee Services (echo-v1 en echo-v2). De echo image komt uit het Kubernetes Gateway API demo image-pad.
kubectl apply -f - <<'YAML'
apiVersion: v1
kind: Namespace
metadata:
name: gateway-infra
---
apiVersion: v1
kind: Namespace
metadata:
name: team-a
labels:
gw-access: "true"
---
apiVersion: v1
kind: Service
metadata:
name: echo-v1
namespace: team-a
labels:
app: echo
version: v1
spec:
selector:
app: echo
version: v1
ports:
- name: http
port: 3000
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-v1
namespace: team-a
spec:
replicas: 1
selector:
matchLabels:
app: echo
version: v1
template:
metadata:
labels:
app: echo
version: v1
spec:
containers:
- name: echo
image: registry.k8s.io/gateway-api/echo-basic:v20251204-v1.4.1
ports:
- containerPort: 3000
env:
- name: VERSION
value: "v1"
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
---
apiVersion: v1
kind: Service
metadata:
name: echo-v2
namespace: team-a
labels:
app: echo
version: v2
spec:
selector:
app: echo
version: v2
ports:
- name: http
port: 3000
targetPort: 3000
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo-v2
namespace: team-a
spec:
replicas: 1
selector:
matchLabels:
app: echo
version: v2
template:
metadata:
labels:
app: echo
version: v2
spec:
containers:
- name: echo
image: registry.k8s.io/gateway-api/echo-basic:v20251204-v1.4.1
ports:
- containerPort: 3000
env:
- name: VERSION
value: "v2"
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
YAML
Expected output / checks:
kubectl -n team-a get svc,deploy
Je ziet echo-v1, echo-v2 services en deployments.
GatewayClass + Gateway (infra-owned)
We maken een GatewayClass die wijst naar Envoy Gateway’s default controllerName gateway.envoyproxy.io/gatewayclass-controller (zie quickstart). Controleer in je cluster altijd of dit overeenkomt met de gebruikte versie.
Vervolgens maken we één Gateway met listeners voor *.example.test, die alleen Routes toestaat uit namespaces met label gw-access=true (dit is meteen een stukje governance: niet from: All). Dit allowedRoutes pattern sluit aan op het Gateway API security model.
kubectl apply -f - <<'YAML'
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-gw
namespace: gateway-infra
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
hostname: "*.example.test"
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gw-access: "true"
YAML
Expected output / checks:
kubectl -n gateway-infra get gateway shared-gw
kubectl -n gateway-infra describe gateway shared-gw
kubectl get gatewayclass eg -o jsonpath='{.spec.controllerName}'; echo
Waar je op let:
Accepted=Trueop de Gateway (de controller heeft ’m geaccepteerd).- In kind zie je vaak dat de top-level Gateway condition
Programmed=Falseis met reasonAddressNotAssigned. Dat komt doordat Envoy Gateway standaard een Service typeLoadBalanceraanmaakt voor de dataplane, en kind geen externe load balancer heeft, waardoorEXTERNAL-IPop<pending>blijft. - Dat betekent niet dat routing niet werkt. Check in dat geval:
status.listeners[].conditionsbevatProgrammed=TrueenAccepted=True, en/of- de proxy Service voor deze Gateway is aangemaakt (zie hieronder) en je kunt die
port-forwarden.
(Optioneel) Proxy Service check:
kubectl -n envoy-gateway-system get svc \
--selector=gateway.envoyproxy.io/owning-gateway-namespace=gateway-infra,gateway.envoyproxy.io/owning-gateway-name=shared-gw
Je ziet dan een Service met TYPE=LoadBalancer en een PORT(S) mapping zoals 80:<nodePort>/TCP. In kind blijft EXTERNAL-IP meestal <pending>.
HTTPRoute maken (host-based + path-based)
We maken één HTTPRoute in team-a die:
- host-based werkt op
app.example.test - path-based split doet:
/v1→echo-v1/v2→echo-v2
kubectl apply -f - <<'YAML'
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: team-a
spec:
parentRefs:
- name: shared-gw
namespace: gateway-infra
hostnames:
- "app.example.test"
rules:
- matches:
- path:
type: PathPrefix
value: /v1
backendRefs:
- name: echo-v1
port: 3000
- matches:
- path:
type: PathPrefix
value: /v2
backendRefs:
- name: echo-v2
port: 3000
YAML
Expected output / checks:
kubectl -n team-a get httproute app-route
kubectl -n team-a get httproute app-route -o yaml
In .status.parents[].conditions wil je in elk geval Accepted=True en ResolvedRefs=True zien. Dat model (Accepted/ResolvedRefs + duidelijke reasons zoals BackendNotFound) is een sterke troubleshooting-indicator.
backendRefs wijzen naar een Service (niet naar een Deployment/Pod) en port is de Service port (niet targetPort).
Traffic splitting / canary (weighted backendRefs)
Weighted routing is onderdeel van Gateway API: spec.rules.backendRefs accepteert een lijst backends met relatieve weight.
Envoy Gateway documenteert dit concreet in de traffic splitting docs.
We maken een tweede HTTPRoute op een ander hostname (canary.example.test) die 90/10 split doet tussen v1 en v2:
kubectl apply -f - <<'YAML'
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
namespace: team-a
spec:
parentRefs:
- name: shared-gw
namespace: gateway-infra
hostnames:
- "canary.example.test"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: echo-v1
port: 3000
weight: 90
- name: echo-v2
port: 3000
weight: 10
YAML
Testen via port-forward
Zonder LoadBalancer in kind gebruik je port-forward naar de Envoy service. De quickstart laat deze selector-methode zien; voeg een fallback toe voor het geval de selector niets teruggeeft.
export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system \
--selector=gateway.envoyproxy.io/owning-gateway-namespace=gateway-infra,gateway.envoyproxy.io/owning-gateway-name=shared-gw \
-o jsonpath='{.items[0].metadata.name}')
kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8888:80
Fallback als ${ENVOY_SERVICE} leeg blijft:
if [ -z "${ENVOY_SERVICE}" ]; then
ENVOY_SERVICE=$(kubectl -n envoy-gateway-system get svc \
-o custom-columns=NAME:.metadata.name,TYPE:.spec.type --no-headers \
| awk '$2=="LoadBalancer" || $2=="NodePort" {print $1; exit}')
fi
if [ -z "${ENVOY_SERVICE}" ]; then
echo "Geen geschikte Envoy Service gevonden. Controleer met:"
echo "kubectl -n envoy-gateway-system get svc"
exit 1
fi
Test host + path routing:
curl -s -H "Host: app.example.test" http://localhost:8888/v1 | head
curl -s -H "Host: app.example.test" http://localhost:8888/v2 | head
Je verwacht output met o.a. host, path, namespace, pod.
Voorbeeld (ingekort):
{"host":"app.example.test","path":"/v1","namespace":"team-a","pod":"echo-v1-6d7b6c8f9f-abcde"}
Test canary split (run dit een paar keer; je zult af en toe een andere backend-pod zien):
for i in $(seq 1 30); do
curl -s -H "Host: canary.example.test" http://localhost:8888/ \
| grep -o 'echo-v[12]-[^"]*' | head -n1
done
Feature-compatibility noot: traffic splitting via
weightis spec-gedefinieerd, maar controllers verschillen in details en conformance. Check altijd de implementatie-matrix en test dit in jouw dataplane.
Delegation & governance: teams autonomie geven zonder cluster-admin
Gateway API is expliciet ontworpen rond personas/roles (infra provider / cluster operator / app developer) zodat je ownership kunt knippen zonder “self-service alles of niets”.
Ownership model: wie beheert wat
Pragmatisch model dat in veel mid/large orgs werkt:
- Platform team (of cluster operator) beheert:
- GatewayClass(es) (cluster-scoped)
- Gateways in een “infra namespace” (listeners, TLS, allowedRoutes, policies)
- Product/app teams beheren:
- HTTPRoute(s) in hun eigen namespace(s)
- Services/Deployments (backends)
In Gateway API zit TLS termination op de Gateway listener (dus typisch niet bij de app developer) en zijn HTTPRoutes app-owned.
Namespaces, RBAC en allowedRoutes: je eerste guardrail
Route attachment is bewust een handshake: routes referencen de Gateway via parentRefs, maar de Gateway listener bepaalt óf routes uit andere namespaces mogen attachen (allowedRoutes). Dit is het “bidirectional trust model” uit de Gateway API docs.
Veilige default bij shared Gateways:
allowedRoutes.namespaces.from: Selectormet een selector op namespace labels- Gebruik bij voorkeur de standaard namespace-name label (
kubernetes.io/metadata.name) of labels die alleen platform kan zetten. - Laat namespace-labels voor gateway-toegang uitsluitend door platform beheren (RBAC op
namespacesupdate/patch) en voer dit via een onboarding-flow uit.
RBAC pattern (schets):
- App team krijgt
update/createop HTTPRoute in eigen namespace - Geen rechten op Gateways in
gateway-infra - Platform team beheert Gateway/GatewayClass en labelt namespaces die mogen attachen (of beheert een “namespace onboarding” flow)
ReferenceGrant: cross-namespace zonder “open bar”
Cross-namespace references zijn default niet toegestaan; de owner van het doel-object moet expliciet grant geven. Dat is precies waarvoor ReferenceGrant bestaat.
Belangrijk nuancepunt uit de spec: “All cross-namespace references … require a ReferenceGrant” (route attachment naar Gateway is een aparte flow).
Praktisch voorbeeld (app team route → shared service):
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-team-a-to-call-shared
namespace: shared-services
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: team-a
to:
- group: ""
kind: Service
Dit pattern staat letterlijk in het Gateway API security model.
Golden path: templates + policy checks (zonder vendor lock-in)
Wat “golden path” hier betekent: app teams leveren HTTPRoute intents aan binnen een strak, gevalideerd kader.
Concreet:
- Templates: een standaard HTTPRoute skeleton (hostnames, parentRefs, filters die je toestaat) + standaard Service ports conventies.
- Policy-as-code checks op commit/PR én bij admission:
- “hostnames moeten onder team-domein vallen”
- “parentRefs alleen naar approved Gateways”
- “geen cross-namespace backendRefs zonder ReferenceGrant”
- “no wildcard hostnames in app namespaces”
Dit soort beperkingen kun je afdwingen met Kubernetes
ValidatingAdmissionPolicy.
Anti-patterns (waar het misgaat)
allowedRoutes.from: Allop een shared Gateway in een multi-team cluster (je geeft implicit iedereen een attach-surface).- Geen duidelijke domein-delegatie per namespace: dit vergroot kans op hostname/domain hijacking scenarios (first-come-first-served conflict resolution + later uitbreiden van hostnames door oudere routes).
- Cross-namespace refs “even toestaan” zonder ReferenceGrant governance: zonder safeguards ontstaan onnodige security-risico’s.
Observability & debugging
Je wil een standaard set signalen, onafhankelijk van controller, plus een paar controller-specifieke plekken.
Signalen die je gebruikt
- Status conditions op Gateway/GatewayClass/HTTPRoute
- GEP-1364 definieert de richting:
Accepted,ResolvedRefs,Programmedals positieve summary conditions, met error-conditions als ze relevant zijn. De exacte set kan per implementatie/feature-level verschillen.
- GEP-1364 definieert de richting:
- Events (
kubectl describe) op Gateway/HTTPRoute: vaak direct “NotAllowed”, “BackendNotFound”, “NoMatchingListenerHostname”, etc. - Controller logs (pas als status/events niet genoeg zijn)
- In kind-setup met
cloud-provider-kind:docker logs cloud-provider-kind. - In Envoy Gateway: logs in
envoy-gateway-system(deployment/pods).
- In kind-setup met
- Controller-specific metrics (verschilt per implementatie; check controller docs).
- Dataplane debugging gotcha: Envoy Gateway quickstart noemt expliciet dat privileged ports gemapt kunnen worden naar unprivileged intern; dat kan verwarrend zijn bij debug.
Checklist: route werkt niet
- Check dat je controller draait (
kubectl -n envoy-gateway-system get po,deploy). kubectl get gatewayclassen check status/Accepted (implementations moeten status populaten).kubectl -n gateway-infra describe gateway shared-gwAccepted=True?Programmed=True? Address gezet?
kubectl -n team-a get httproute app-route -o yamlstatus.parents[].conditions:Accepted,ResolvedRefs?
- Hostname match: HTTPRoute
hostnamesmoeten matchen met de Gateway listenerhostname(anders wordt het genegeerd). - allowedRoutes match: komt je route-namespace door de selector?
allowedRoutessemantics staan in de Gateway API spec reference. - Backend bestaat + juiste port:
BackendNotFound/ResolvedRefs=Falseis een typisch signaal. - Cross-namespace backendRefs? Dan: bestaat de ReferenceGrant in target namespace? Zonder grant is de reference invalid.
- Controller-specific constraints: bij Envoy Gateway zijn backendRefs (nu) vooral Service-only; invalid backendRefs kunnen resulteren in HTTP 500 voor het traffic-deel dat naar die backend zou gaan (bij traffic splitting).
- Pas dan: controller logs + reconcile errors.
Veelvoorkomende failure modes
- Hostname mismatch (Gateway listener vs HTTPRoute hostnames): route “lijkt” te bestaan maar wordt genegeerd.
- Namespace niet toegestaan door allowedRoutes selector:
Accepted=False/ “NotAllowedByListeners” (semantics + security guidance). - Missing ReferenceGrant bij cross-namespace backendRefs:
ResolvedRefs=Falseof controller reject; dit is by design. - Conflicts / hostname claim hijacking als je “te breed” delegate en geen policy-checks hebt.
- Controller quirks: bijvoorbeeld Envoy Gateway’s privileged-port mapping.
Migratieplan zonder big-bang
De Gateway API migratiegids helpt goed met concept mapping en handmatige conversie, maar niet volledig met live migratie en controller-specifieke features. Daar maken migratie-aanpak en governance het verschil.
Hier is een plan dat werkt in echte clusters.
Parallel draaien: Ingress en Gateway naast elkaar
- Laat je bestaande Ingress controller draaien (meestal) terwijl je Gateway API controller uitrolt in parallel.
- Gebruik de Gateway API om nieuwe routes op te zetten, of een beperkte subset van bestaande routes.
- Belangrijk: Ingress API verdwijnt niet uit Kubernetes (frozen maar blijft GA), dus parallel runnen is een legitieme stap.
Canary routes / beperkte hostnames
Start klein met blast radius:
- Kies een subdomein of dedicated hostname-set, bv.
gw.example.comof*.gw.example.com, en route alleen dat via Gateway. - Of gebruik een beperkt aantal apps/teams die adopter willen zijn.
Gateway API ondersteunt traffic splitting met weights op HTTPRoute backendRefs, wat je inzet voor canary rollouts.
Als jouw controller (nog) geen weights ondersteunt:
- Gebruik host-based canary (
canary.app.example.com) of header-based routing (als ondersteund) als alternatief, en houd het “split” mechanisme buiten de data plane (bijv. DNS weighted records). (Controller-support varieert per implementatie; check implementations/conformance.)
TLS-migratie: certs en secrets
- Verplaats TLS-terminatie expliciet naar Gateway listeners en inventariseer welke certs nu via Ingress lopen.
- Bepaal waar TLS Secrets beheerd worden (bijv.
cert-managerof handmatig) en migreer die gecontroleerd mee. - Gebruik
ReferenceGrantals je cross-namespace Secret-references nodig hebt; zonder grant blijft zo’n reference ongeldig. - Valideer na migratie minimaal: SNI/hostname match, volledige cert chain, en renewal-flow.
Hostname ownership expliciet maken
- Reserveer domein-slices per team (bijv.
team-a.example.com). - Forceer dit met admission/policy: hostnames binnen team-scope, geen wildcard hostnames in app-namespaces, en alleen approved
parentRefs. - Leg conflicts afhandelregels vast (wie krijgt voorrang bij overlap) voordat teams zelfstandig routes publiceren.
Rollback plan
Rollback moet “saai” zijn:
- Houd Ingress resources intact en “toggle” traffic terug via:
- DNS terug naar oude entrypoint, of
- load balancer/service switch (afhankelijk van infra), of
- hostnames terug laten wijzen naar Ingress endpoint.
- Gebruik dezelfde acceptance checks (zie hieronder) om rollback te valideren.
Wanneer ben je “done”
Acceptance criteria (maak dit expliciet, anders blijf je zweven):
- Functioneel:
- Alle externe routes zijn gemigreerd en gevalideerd (host/path/TLS/redirects/etc).
- Geen dependency meer op controller-specifieke Ingress annotations voor core routing.
- Governance:
- Gateway (infra) ownership en HTTPRoute (app) ownership liggen vast, inclusief RBAC en namespace onboarding flow. Dit sluit aan op het persona-model dat Gateway API expliciet maakt.
- allowedRoutes en (waar nodig) ReferenceGrant policies staan als guardrails.
- Operability:
- Runbooks: “route doet het niet” checklist, standaard dashboards/alerts op gateway dataplane, en duidelijke escalatie naar platform team.
- Decommission:
- Als je community ingress-nginx gebruikte: plan expliciet voor de retirement datum (maart 2026) i.v.m. security posture.
Verder lezen
- Ingress concepten (Kubernetes): https://kubernetes.io/docs/concepts/services-networking/ingress/
- Gateway API docs: https://gateway-api.sigs.k8s.io/
- Migreren vanaf Ingress: https://gateway-api.sigs.k8s.io/guides/migrating-from-ingress/
- Gateway API security model: https://gateway-api.sigs.k8s.io/concepts/security-model/
- Gateway API spec reference (
allowedRoutes,parentRefs,backendRefs): https://gateway-api.sigs.k8s.io/reference/spec/ - GEP-1364 (status/conditions): https://gateway-api.sigs.k8s.io/geps/gep-1364/
- Envoy Gateway quickstart: https://gateway.envoyproxy.io/docs/tasks/quickstart/
- Community ingress-nginx retirement aankondiging: https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/
Conclusie
Gateway API is vooral een operational upgrade: minder “alles-in-één Ingress object”, meer duidelijke contracten tussen infra en apps, met status-driven debugging en betere multi-team guardrails.
Samenvatting in 5 bullets:
- Ingress is stable maar “frozen”; Kubernetes raadt Gateway aan voor nieuwe capabilities en organisatie-fit.
- Gateway API knipt ownership: GatewayClass/Gateway infra-owned, HTTPRoute app-owned; dat matcht real-world teamstructuren.
- allowedRoutes + ReferenceGrant geven je een echte multi-tenant security handshake (niet “open bar”).
- Status conditions (
Accepted,ResolvedRefs,Programmed) zijn je primaire debug-interface. - Migratie zonder big-bang: run parallel, begin met beperkte hostnames/canary weights, en maak “done” meetbaar.