Gateway API
The successor to Ingress. GA and the recommended path for new work, while Ingress remains supported but effectively frozen. Answering a Kubernetes traffic question with only Ingress dates you.
Why Ingress needed replacing
Ingress solved HTTP routing in 2016 and then stopped evolving. Its problems compounded:
- Annotation sprawl. Anything beyond host and path routing — timeouts, rewrites, rate limits, canary weights — lived in vendor-specific annotations. An nginx-ingress manifest doesn’t work on Traefik or an AWS ALB controller.
- No portability. The spec covered so little that every controller invented its own extensions, so “we use Ingress” told you almost nothing.
- One role. A single resource mixed infrastructure concerns (which load balancer, which certificate) with application concerns (which path goes where), so platform teams and application teams contended over the same object.
- HTTP only. No first-class TCP, UDP or gRPC.
The model
Gateway API splits one resource into three, along organisational lines:
GatewayClass <- infrastructure provider (platform team, cluster-scoped)
|
Gateway <- a listener: port, protocol, TLS (platform/ops)
|
HTTPRoute <- routing rules (application team, namespaced)
That separation is the design’s real point: the person who owns TLS and load balancers isn’t the person who owns /api/v2 routing. Role-oriented design, not just a richer schema.
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-gateway
namespace: infra
spec:
gatewayClassName: envoy
listeners:
- name: https
protocol: HTTPS
port: 443
tls:
certificateRefs: [{ name: prod-tls }]
allowedRoutes:
namespaces:
from: Selector # which namespaces may attach routes
selector:
matchLabels: { gateway-access: "true" }
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api
namespace: team-payments
spec:
parentRefs: [{ name: prod-gateway, namespace: infra }]
hostnames: ["api.example.com"]
rules:
- matches:
- path: { type: PathPrefix, value: /payments }
backendRefs:
- name: payments-v1
port: 8080
weight: 90
- name: payments-v2 # canary, in the spec - no annotations
port: 8080
weight: 10
What’s in the spec that used to be annotations
| Capability | Ingress | Gateway API |
|---|---|---|
| Header/method/query matching | annotations | spec |
| Traffic splitting / canary | annotations | weight |
| Header modification | annotations | filters |
| Redirects and rewrites | annotations | filters |
| Request mirroring | rarely | filter |
| TCP, UDP, gRPC routing | no | TCPRoute, UDPRoute, GRPCRoute |
| Cross-namespace routing | no | ReferenceGrant |
Weighted traffic splitting in the spec is the one to name — progressive delivery without a service mesh or vendor annotations. See ../27_cicd/08_progressive_delivery.md.
Cross-namespace references
A route in one namespace attaching to a Gateway in another is explicitly controlled from both directions: the Gateway’s allowedRoutes says who may attach, and a ReferenceGrant in the target namespace permits references to its Services.
This is a genuine security improvement — Ingress had no way to express “team A may route to this Gateway but not to team B’s services”.
Migrating
- Install the Gateway API CRDs and a controller (Envoy Gateway, Istio, Cilium, NGINX Gateway Fabric, or a cloud controller).
- Create a
Gatewayalongside your existing Ingress. - Convert routes incrementally — both can serve traffic during migration.
- Cut DNS over, then remove the Ingress.
ingress2gateway converts existing manifests as a starting point; vendor annotations still need manual translation, since that’s precisely what wasn’t portable.
Ingress is not deprecated and will keep working. But it receives no new features, so anything you want beyond basic routing is either a vendor annotation or a reason to move.
Interview angle
- “How do you expose a service outside the cluster?” — Service type LoadBalancer for L4, and for HTTP the Gateway API, which is GA and the recommended path. Ingress still works but is feature-frozen, so new capability lands only in Gateway API.
- “What was wrong with Ingress?” — the spec covered so little that everything real lived in vendor-specific annotations, which killed portability. It also mixed infrastructure and application concerns in one resource, so platform and app teams contended over it, and it was HTTP-only.
- “What does Gateway API change structurally?” — three resources split by role: GatewayClass for the provider, Gateway for listeners/ports/TLS owned by the platform team, and HTTPRoute for routing owned by application teams in their own namespaces.
- “How would you do a canary deployment with it?” —
backendRefswith weights in the HTTPRoute spec. No annotations, no service mesh required, and it’s portable across controllers. - “How do you stop one team routing to another team’s services?” —
allowedRouteson the Gateway controls which namespaces may attach, andReferenceGrantin the target namespace permits cross-namespace backend references. Both sides must agree, which Ingress couldn’t express. - “Do you have to migrate?” — no, Ingress keeps working. You migrate when you want features that will only ever exist in Gateway API, and you can run both side by side during the transition.