Networking

Gateway API

● Advanced ⏱ 15 min read

The Ingress API was designed in 2015 for one use case: routing HTTP traffic. Ten years later, clusters handle gRPC, TCP, canary deployments, and multi-team traffic management — all through annotation hacks. Gateway API (GA in Kubernetes 1.31) is the official replacement: typed resources, role separation, and native support for all protocols.

Why Gateway API

The Ingress API has three structural problems that can't be fixed by adding fields:

Gateway API solves all three by splitting responsibilities across three separate resource types, each owned by a different team.

The Three Resources

Gateway API ownership model
Cluster Admin
GatewayClass
cluster-scoped · names the controller
Declares that a controller (e.g. nginx, istio) is available to provision Gateways. Created once by the platform team.
Infra Team
Gateway
namespace-scoped · provisions LB
Defines listener ports, protocols, and TLS config. References a GatewayClass. The controller provisions a real load balancer.
App Team
HTTPRoute
namespace-scoped · routing rules
Defines hostname matching, path rules, header filters, traffic weights, and which backend Services receive traffic.
Each team owns their layer. App teams deploy HTTPRoutes without touching Gateway config.
Gateway API separates concerns across three resource types. The infrastructure team controls the Gateway; app teams control their HTTPRoutes.

GatewayClass

A GatewayClass names a controller that knows how to provision Gateways. It's cluster-scoped — one instance per controller type. The controller implementation watches for Gateways that reference its class and provisions the underlying infrastructure.

gatewayclass.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nginx
spec:
  controllerName: k8s.nginx.org/nginx-gateway-controller

Most cloud providers and popular controller projects (nginx, Istio, Envoy, Traefik, Cilium) already ship GatewayClass definitions. After installing the controller, the GatewayClass should appear in your cluster automatically.

Gateway

A Gateway declares one or more listeners — combinations of port, protocol, and optional hostname. The controller provisions a load balancer or configures an existing one to match these listeners.

gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-gateway
  namespace: infra
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    port: 80
    protocol: HTTP
  - name: https
    port: 443
    protocol: HTTPS
    tls:
      mode: Terminate
      certificateRefs:
      - name: example-tls    # Secret in the same namespace
    # restrict which namespaces can attach HTTPRoutes
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            gateway-access: allowed

The allowedRoutes field is a key multi-tenancy feature: the infra team controls which namespaces can attach routes to this Gateway. App teams can't "steal" capacity from a Gateway they aren't allowed to use.

HTTPRoute

HTTPRoute defines the routing rules that would previously live in an Ingress spec (host matching, path matching) plus features that previously required annotations (header matching, response modification, redirects).

httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-route
  namespace: production    # app team's namespace
spec:
  parentRefs:
  - name: prod-gateway
    namespace: infra       # attach to the Gateway
    sectionName: https     # attach to the "https" listener only
  hostnames:
  - "api.example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1
    filters:
    - type: RequestHeaderModifier
      requestHeaderModifier:
        add:
        - name: X-Version
          value: "1"
    backendRefs:
    - name: api-v1
      port: 8080
  - matches:
    - path:
        type: PathPrefix
        value: /v2
    backendRefs:
    - name: api-v2
      port: 8080

Traffic Splitting

Traffic splitting with weights is a first-class feature — no annotations, no controller-specific YAML. Useful for canary deployments and A/B testing.

canary-split.yaml
spec:
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: api-stable   # current production version
      port: 8080
      weight: 90         # 90% of traffic
    - name: api-canary   # new version under test
      port: 8080
      weight: 10         # 10% of traffic

Adjust the weights without redeploying the app — just update the HTTPRoute. Gradually shift from 10% to 50% to 100% as confidence builds, then remove the stable backend.

Other Route Types

Gateway API supports multiple route types for different protocols:

Route typeProtocolStatusUse case
HTTPRouteHTTP/HTTPSGA (v1)Web apps, REST APIs, redirects, header rewrites
GRPCRoutegRPCGA (v1)gRPC services, method-level routing
TLSRouteTLS (passthrough)ExperimentalNon-HTTP TLS traffic forwarded by SNI
TCPRouteRaw TCPExperimentalDatabases, custom protocols (no SNI)
UDPRouteUDPExperimentalDNS, QUIC, game servers

TLS with Gateway API

TLS configuration moves from Ingress annotations into the Gateway's listener spec. The Gateway references a TLS Secret for the certificate. Cert-manager already supports Gateway API — add the annotation to auto-provision certificates:

# Gateway listener (infra team)
listeners:
- name: https
  port: 443
  protocol: HTTPS
  tls:
    mode: Terminate
    certificateRefs:
    - name: example-tls   # Secret with tls.crt and tls.key

# cert-manager auto-provisions this Secret when you annotate the Gateway:
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod

Migrating from Ingress

Ingress and Gateway API can coexist in the same cluster during migration. Most major controllers support both. The migration path:

  1. Install a controller that supports Gateway API (e.g. nginx-gateway-fabric, Istio, Envoy Gateway)
  2. Create a GatewayClass and Gateway to mirror your Ingress configuration
  3. Convert Ingress rules to HTTPRoute resources one namespace at a time
  4. Update DNS to point to the Gateway's IP once routes are verified
  5. Remove the old Ingress resources
💡
No urgency to migrate

Ingress is not deprecated and has no planned removal date. Migrate when you need features Gateway API provides natively (traffic splitting, gRPC routing, header manipulation, multi-team separation) — not just to be on the latest API.

kubectl Commands

# Install Gateway API CRDs (required before using any Gateway resources)
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml

# List GatewayClasses (cluster-scoped)
kubectl get gatewayclass

# List Gateways
kubectl get gateway -A

# Describe a Gateway (shows listeners, assigned addresses, conditions)
kubectl describe gateway prod-gateway -n infra

# List HTTPRoutes
kubectl get httproute -A

# Describe an HTTPRoute (shows rules, parent refs, backend status)
kubectl describe httproute api-route -n production

# Check if a route was accepted by the Gateway
kubectl get httproute api-route -n production \
  -o jsonpath='{.status.parents[*].conditions}'