Gateway API
Gateway API
A NodePort per application does not scale: you end up remembering that the shop is on 30080 and the wiki on 30081. You want one HTTP entry point that routes by host name and path.
Kubernetes has had two answers to that. Ingress is the old one - stable, but frozen: every controller extended it with its own annotations, so a rewrite rule for nginx means nothing to Traefik. Gateway API is the replacement: the same job expressed as real, typed resources, and it is where all the development now happens.
Three objects, three owners
| Object | Answers | Usually owned by |
|---|---|---|
| GatewayClass | which implementation handles this? | the cluster admin, installed with the controller |
| Gateway | where does traffic enter - ports, protocols, TLS | the platform team |
| HTTPRoute | which requests go to which Service | the application team |
That split is the real point. With Ingress, one object mixed infrastructure and
application concerns, so either developers edited shared infrastructure or the
platform team became a ticket queue. Here a team can own its HTTPRoute and
attach it to a Gateway it is allowed to use - and the Gateway decides, via
allowedRoutes, who may attach.
The objects
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: web-gw
spec:
gatewayClassName: nginx
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: shop
spec:
parentRefs:
- name: web-gw
hostnames: ["shop.k8s.lab"]
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: shop-svc
port: 80
An HTTPRoute attaches itself to a Gateway with parentRefs - the route points
up, the Gateway does not list its routes. That is what lets a team add a route
without touching shared config.
What you get that Ingress could not express
- Traffic splitting - two
backendRefswith weights, so 90/10 canary releases are a core field, not an annotation. - Header, method and query matching - not just host and path.
- Header rewriting and redirects as typed filters.
- Other protocols -
TCPRoute,GRPCRoute,TLSRoute. - Cross-namespace routing with an explicit permission model.
backendRefs: # canary, no annotations required
- name: shop-v1
port: 80
weight: 90
- name: shop-v2
port: 80
weight: 10
Still two pieces
The resources are only data. A controller must be installed to read them and run a proxy - NGINX Gateway Fabric, Envoy Gateway, Traefik, Cilium, or a cloud load balancer. And unlike Ingress, the CRDs are not part of Kubernetes: you install the Gateway API CRDs first, then the controller. Lab 15 does both.
A Gateway with no controller stays PROGRAMMED: False and no traffic flows -
the same silent failure as an Ingress with no controller, but at least the
status field tells you.
And the controller is itself two things, which is worth knowing before you go looking for it:
| Where it lives | Service type | |
|---|---|---|
| Control plane | the namespace you installed the chart into | ClusterIP - it only talks to its agents |
| Data plane (the actual proxy) | created per Gateway, in the Gateway’s namespace | what you configured: NodePort or LoadBalancer |
So there is no proxy at all until you create a Gateway, and when you do, it does not appear next to the controller. Looking for your NodePort in the controller’s namespace and finding a ClusterIP is the single most common false alarm with this implementation.
How traffic arrives here
The controller needs its own entry point. In a cloud that is a LoadBalancer
Service; in this cluster it is a NodePort, so the browser talks to
http://worker01:<nodeport> with a Host: header.
Should you still learn Ingress?
You will meet it - it is in every existing cluster and it is not being removed. But new work belongs on Gateway API, and most controllers can be told to read both while you migrate.