13.7 The Gateway API: The Future Beyond Ingress
Alright, let’s talk about the future. You remember Ingress, right? The resource we just spent a chapter on? It’s… fine. It got us this far. But it’s a bit like trying to run a modern logistics company using a map drawn on a napkin. It works for basic “send this truck from A to B” stuff, but the moment you need complex routing, traffic splitting, or any semblance of a standard interface, you’re duct-taping annotations to it and praying.
Enter the Gateway API. This isn’t just an upgrade; it’s a fundamental re-think. It’s a collection of Kubernetes resources—GatewayClass, Gateway, HTTPRoute, and more—that model service networking in a way that’s actually, well, Kubernetes-native. It separates the concern of infrastructure (what implements the routing) from the concern of application (what traffic needs to be routed). This separation is its superpower.
The Core Trio: GatewayClass, Gateway, and HTTPRoute
Think of these three resources as the owner, the landlord, and the tenant.
A GatewayClass is defined by your cluster admin. It describes a class of gateways available in the cluster, like “this cluster has an option for NGINX gateways” or “we’ve got a fancy cloud-provider load balancer option here.” It’s the menu of available infrastructure. As an application developer, you’ll probably just consume these.
# This is typically set up by your cluster admin. You just need to know it exists.
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: nginx-class
spec:
controllerName: ingress-nginx.github.io/controller
The Gateway is your instantiation of that class. You define this. It’s the actual provisioned piece of infrastructure. When you create this, your chosen controller (e.g., the ingress-nginx one) sees it and says, “Right then, time to spin up a LoadBalancer Service and a Deployment of my pods to handle traffic for this guy.”
# You define this. It says "I want a Gateway of class 'nginx-class' that listens on port 443"
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-app-gateway
namespace: default
spec:
gatewayClassName: nginx-class
listeners:
- name: https
port: 443
protocol: HTTPS
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
purpose: routing
Notice the allowedRoutes section. This is a huge security and tenant isolation win over Ingress. This Gateway will only accept routes from namespaces labeled with purpose: routing. My gateway in the default namespace doesn’t have to accept routes from your sketchy namespace. This is a big deal.
Finally, the HTTPRoute is where you, the application developer, do your magic. It’s a route that attaches to a Gateway. This is the tenant that rents space from the landlord (Gateway). It’s decoupled. You can create these in your own namespace without needing access to the Gateway itself, as long as the Gateway’s policy allows it.
A Practical HTTPRoute Example
Let’s create a route that sends 90% of traffic to the stable version of our app and 10% to a canary. This was a nightmare with standard Ingress; here, it’s a first-class citizen.
# This lives in your application's namespace, e.g., 'app-team-alpha'
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: canary-route
namespace: app-team-alpha
spec:
parentRefs:
- name: my-app-gateway # References the Gateway defined earlier
namespace: default
hostnames:
- "myapp.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app-stable
port: 80
weight: 90
- name: my-app-canary
port: 80
weight: 10
Boom. Traffic splitting, done. No arcane annotations, just a clear, declarative API. The parentRefs points to our landlord Gateway, and the rules define what to do with incoming requests.
Why This is Objectively Better
First, separation of duties. Cluster admins manage GatewayClass and Gateway resources, controlling the infrastructure. App teams manage HTTPRoute resources in their own namespaces, controlling their own traffic. This is how multi-tenant clusters should work.
Second, portability. Your HTTPRoute manifest is far less likely to be littered with implementation-specific nonsense. It describes the intent (“route traffic for this host, split it like this”) rather than the implementation (“set this specific NGINX variable”). This makes it more portable across different Gateway providers.
Third, rich matching. The HTTPRoute API allows for matching on far more than just host and path. You can match on headers, query parameters, and even HTTP methods, which opens up incredibly powerful routing scenarios that required middleware or custom code before.
The Rough Edges and Pitfalls
It’s not all rainbows. The GatewayClass and Gateway are cluster-scoped resources. If your admin hasn’t set one up, you’re stuck. You can’t just kubectl apply an Ingress and have it mostly work; the underlying infrastructure must be pre-configured and available.
Also, mind the allowedRoutes configuration on your Gateway. It’s a common foot-gun to create a perfect HTTPRoute and forget that the Gateway it’s referencing is actively rejecting routes from your namespace. Always check the Gateway’s .status conditions; it’s usually pretty good about telling you why it’s ignoring your route.
The API is also still evolving. While the core HTTPRoute is generally available (v1), other route types (TCPRoute, UDPRoute) are still in beta. And some more advanced features you might crave might only be implemented by certain providers. Always check the conformance and implementation status of your chosen controller.
But these are growing pains. The Gateway API is the unequivocal future of traffic management in Kubernetes. It’s the map replaced by a real-time GPS. Start using it now. Your future self, who isn’t debugging bizarre annotation conflicts, will thank you.