Kubernetes Gateway API Reference: HTTPRoute, GatewayClass, Traffic Splitting & GRPCRoute
Kubernetes Gateway API is the successor to Ingress — richer, more expressive, and role-based. It graduated to GA (v1) in K8s 1.28. HTTPRoute, GRPCRoute, TCPRoute and more replace the single Ingress spec, while Gateway is the infrastructure object that cluster operators control separately from app developers.
1. Gateway API vs Ingress
Why Gateway API exists and how it maps to Ingress concepts
| Concept | Ingress | Gateway API |
|---|---|---|
| Infrastructure config | IngressClass (basic) | GatewayClass — controller-specific |
| Listener + TLS | Ingress.spec.tls | Gateway — defines listeners + TLS |
| Routing rules | Ingress.spec.rules | HTTPRoute / GRPCRoute / TCPRoute |
| Role separation | Single resource, often one owner | GatewayClass (cluster admin), Gateway (platform), Routes (developers) |
| Traffic splitting | Annotation hack (nginx-specific) | First-class backendRefs weights |
| Header matching | Annotation-based | Native spec fields |
| Status | Stable (GA since K8s 1.1) | GA (v1) since K8s 1.28 |
# Install Gateway API CRDs (required before using any implementation): kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml # Implementations (pick one — they provide the GatewayClass): # - Envoy Gateway: envoyproxy/gateway # - Cilium: uses eBPF, no proxy # - Istio: full service mesh + Gateway API # - Kong: ingress-kong # - Traefik: traefik/traefik (v3+) # - NGINX Gateway Fabric: nginxinc/nginx-gateway-fabric # Install Envoy Gateway (popular, lightweight): helm install eg oci://docker.io/envoyproxy/gateway-helm --namespace envoy-gateway-system --create-namespace --version v1.1.2
2. GatewayClass, Gateway & HTTPRoute
Core objects — the three-layer separation of concerns
# GatewayClass (cluster admin — declares which controller handles Gateways):
# Created automatically by Envoy Gateway / Cilium / etc. after install
# List available: kubectl get gatewayclass
# Gateway (platform team — defines listeners, ports, TLS):
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-gateway
namespace: gateway-infra
spec:
gatewayClassName: eg # matches GatewayClass name from controller
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Selector # only allow routes from labeled namespaces
selector:
matchLabels:
gateway-access: "true"
- name: https
port: 443
protocol: HTTPS
tls:
certificateRefs:
- kind: Secret
name: wildcard-tls # TLS cert from cert-manager
allowedRoutes:
namespaces:
from: All
# HTTPRoute (app developer — defines routing rules):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: production
spec:
parentRefs:
- name: prod-gateway
namespace: gateway-infra # reference to Gateway above
hostnames:
- api.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /api
backendRefs:
- name: api-service
port: 8080
3. Traffic Splitting & Header Matching
Canary by weight, A/B by header, and URL rewrites — all in spec
# Traffic splitting by weight (canary — no annotations needed):
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-canary
namespace: production
spec:
parentRefs:
- name: prod-gateway
namespace: gateway-infra
hostnames: [api.example.com]
rules:
- matches:
- path: {type: PathPrefix, value: /api}
backendRefs:
- name: api-service-stable
port: 8080
weight: 90 # 90% of traffic
- name: api-service-canary
port: 8080
weight: 10 # 10% to canary
# Header-based routing (A/B testing, beta users):
rules:
- matches:
- headers:
- name: X-Beta-User
value: "true"
backendRefs:
- name: api-service-beta
port: 8080
- backendRefs: # default (no match)
- name: api-service-stable
port: 8080
# URL rewrite (strip /api prefix):
rules:
- matches:
- path: {type: PathPrefix, value: /api}
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: / # strip /api prefix
backendRefs:
- name: api-service
port: 8080
4. TLS with cert-manager & ReferenceGrant
Cross-namespace TLS secrets and cert-manager ClusterIssuer integration
# Gateway references TLS cert from cert-manager:
# cert-manager automatically creates the Secret when it sees a Gateway with:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: prod-gateway
namespace: gateway-infra
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod # trigger auto-cert
spec:
listeners:
- name: https
port: 443
protocol: HTTPS
hostname: "*.example.com"
tls:
certificateRefs:
- name: wildcard-example-cert # cert-manager creates this
# ReferenceGrant — allow HTTPRoute in 'production' to reference backend in 'backend-ns':
# (Gateway API cross-namespace references need explicit grants)
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-production-routes
namespace: backend-ns # namespace BEING referenced
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: production # namespace doing the referencing
to:
- group: ""
kind: Service
# Check Gateway + HTTPRoute status:
kubectl get gateway prod-gateway -n gateway-infra -o yaml | grep -A10 status
kubectl get httproute -A # list all routes
kubectl describe httproute api-route -n production # conditions + events
5. GRPCRoute & TCPRoute
Route gRPC services and raw TCP — beyond HTTP
# GRPCRoute (GA in v1.1.0) — route gRPC traffic with service/method matching:
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: grpc-route
namespace: production
spec:
parentRefs:
- name: prod-gateway
namespace: gateway-infra
hostnames: [grpc.example.com]
rules:
- matches:
- method:
service: user.UserService # full gRPC service name
method: GetUser # specific method (optional — omit to match all)
backendRefs:
- name: user-grpc-service
port: 50051
- matches:
- method:
service: order.OrderService # all methods on OrderService
backendRefs:
- name: order-grpc-service
port: 50051
# TCPRoute (experimental) — raw TCP passthrough (databases, custom protocols):
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: postgres-route
namespace: data
spec:
parentRefs:
- name: prod-gateway
namespace: gateway-infra
sectionName: postgres-listener # must have TCP listener on Gateway
rules:
- backendRefs:
- name: postgres-service
port: 5432
# Add TCP listener to Gateway for TCPRoute:
# - name: postgres-listener
# port: 5432
# protocol: TCP
# allowedRoutes:
# namespaces: {from: Selector}
Track Kubernetes Gateway API and Kubernetes releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: NGINX Ingress Controller Reference | Kubernetes YAML Reference | cert-manager Reference
🔍 Free tool: K8s YAML Security Linter — check Gateway API manifests — HTTPRoute, GRPCRoute — for K8s security misconfigurations.
Founded
2023 in London, UK
Contact
hello@releaserun.com