K8s Gateway API: Ingress Evolved
Kubernetes Ingress served us well, but its limitations are real. The Gateway API is the evolution—more expressive, more portable, more powerful. It’s now GA and ready for production.
The Problem with Ingress
Ingress was designed for simple HTTP routing:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple
spec:
rules:
- host: example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
Limitations:
- No standard TCP/UDP routing
- No traffic splitting
- Vendor-specific annotations
- Limited role separation
- No header-based routing
Gateway API Architecture
┌─────────────────┐
│ GatewayClass │ ← Infrastructure provider config
└────────┬────────┘
│
┌────────▼────────┐
│ Gateway │ ← Listener configuration (ports, TLS)
└────────┬────────┘
│
┌────────▼────────┐
│ HTTPRoute │ ← Routing rules
│ GRPCRoute │
│ TCPRoute │
│ TLSRoute │
└─────────────────┘
Core Concepts
GatewayClass
Defines the controller:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: istio
spec:
controllerName: istio.io/gateway-controller
Think of it as the “CSI driver” for networking.
Gateway
The actual load balancer:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production
spec:
gatewayClassName: istio
listeners:
- name: https
port: 443
protocol: HTTPS
tls:
certificateRefs:
- name: prod-cert
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway: production
HTTPRoute
The routing rules:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-routes
spec:
parentRefs:
- name: production
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /v1
backendRefs:
- name: api-v1
port: 80
- matches:
- path:
type: PathPrefix
value: /v2
backendRefs:
- name: api-v2
port: 80
Advanced Features
Traffic Splitting
Canary deployments natively:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
spec:
rules:
- backendRefs:
- name: api-v1
port: 80
weight: 90
- name: api-v2
port: 80
weight: 10
Header-Based Routing
rules:
- matches:
- headers:
- name: x-api-version
value: beta
backendRefs:
- name: api-beta
port: 80
Request Modification
rules:
- filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Custom-Header
value: added-by-gateway
remove:
- X-Debug-Header
backendRefs:
- name: backend
port: 80
Redirects
rules:
- matches:
- path:
type: Exact
value: /old-path
filters:
- type: RequestRedirect
requestRedirect:
path:
type: ReplaceFullPath
replaceFullPath: /new-path
statusCode: 301
Role-Based Access
Gateway API separates concerns:
| Role | Resources | Typical Owner |
|---|---|---|
| Infrastructure | GatewayClass | Platform team |
| Cluster Ops | Gateway | SRE/Ops |
| App Developer | HTTPRoute | Dev teams |
Developers can create routes without touching Gateway config.
Cross-Namespace References
# In app-namespace
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app
namespace: app-namespace
spec:
parentRefs:
- name: production
namespace: gateway-namespace # Different namespace
With proper RBAC, teams manage their own routes.
TCP and gRPC
Not just HTTP:
# TCP routing
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
spec:
parentRefs:
- name: tcp-gateway
rules:
- backendRefs:
- name: postgres
port: 5432
# gRPC routing
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
spec:
parentRefs:
- name: production
rules:
- matches:
- method:
service: myservice.MyService
method: MyMethod
backendRefs:
- name: grpc-service
port: 50051
Migration from Ingress
Step 1: Install Gateway Controller
Choose your implementation:
- Istio
- Envoy Gateway
- Cilium
- Kong
- NGINX Gateway Fabric
Step 2: Create GatewayClass and Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: main
spec:
gatewayClassName: your-provider
listeners:
- name: http
port: 80
protocol: HTTP
Step 3: Convert Ingress to HTTPRoute
# Before: Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
spec:
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
# After: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app
spec:
parentRefs:
- name: main
hostnames:
- app.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app
port: 80
Step 4: Gradual Rollover
Run both in parallel. Switch DNS. Remove Ingress.
Should You Migrate?
Migrate now if:
- Starting new clusters
- Need traffic splitting
- Want cross-namespace routing
- Using supported controllers
Wait if:
- Ingress works fine for your needs
- Your controller doesn’t support Gateway API yet
- Limited testing capacity
Final Thoughts
Gateway API is the future of Kubernetes networking. It’s more expressive, more portable, and better designed than Ingress.
Start learning it now. Migrate when your controller supports it. Enjoy the cleaner abstractions.
Better APIs make better platforms.