Runtime Zero
ESC
Browse by topic
Articles  /  Kubernetes

Kubernetes Gateway API vs Ingress: What You Need to Know

Gateway API is GA and production-ready. It fixes the limitations of Ingress that have frustrated teams for years. Here's a concrete comparison and a migration guide for Nginx Ingress users.

LP

The Kubernetes Gateway API reached GA in October 2023, and a year later it's clear that it's the future of traffic management in Kubernetes. If you're still using Ingress resources, here's why you should start planning a migration — and what the path looks like.

What Was Wrong with Ingress

The Ingress resource was designed for a simpler era. Its core problems:

Vendor-specific annotations: Every feature beyond path-based routing required controller-specific annotations. An Nginx-specific rate limiting annotation doesn't work on Traefik, and vice versa. Your Ingress manifests became tightly coupled to your controller choice.

No role separation: A single Ingress resource conflates infrastructure concerns (TLS cert, load balancer class) with application concerns (path routing, headers). There's no way to let application teams edit routing rules without also granting access to infrastructure configuration.

Limited traffic manipulation: Ingress has no native concept of request mirroring, traffic splitting, or header-based routing. All of these required non-portable annotations.

Gateway API's Three-Resource Model

Gateway API splits the concerns across three resources, mapped to three roles:

GatewayClass (infra admin) → defines the controller implementation
     ↓
Gateway (platform team) → defines listener config, TLS, load balancer
     ↓
HTTPRoute (app team) → defines routing rules for one service
# Platform team: defines the gateway
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-gateway
  namespace: infra
spec:
  gatewayClassName: cilium
  listeners:
    - name: https
      port: 443
      protocol: HTTPS
      tls:
        certificateRefs:
          - name: wildcard-tls
            namespace: infra
      allowedRoutes:
        namespaces:
          from: All
---
# App team: defines routing (no access to the Gateway object needed)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: payments-route
  namespace: payments
spec:
  parentRefs:
    - name: prod-gateway
      namespace: infra
  hostnames:
    - payments.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: payments-api
          port: 8080

The application team never touches the Gateway or the TLS cert — they only write HTTPRoute. The platform team controls the gateway configuration without needing to understand each application's routing.

Traffic Splitting (Canary Deployments)

This is where Gateway API shines compared to Ingress:

rules:
  - backendRefs:
      - name: payments-api-stable
        port: 8080
        weight: 90
      - name: payments-api-canary
        port: 8080
        weight: 10

Native weight-based traffic splitting without annotations, without service mesh, without any controller-specific features. This works with any Gateway API-compatible implementation.

Migration from Nginx Ingress

The migration is mechanical for simple Ingress resources:

Ingress HTTPRoute equivalent
host: + path: hostnames: + matches[].path
tls: block Moved to Gateway listener
nginx.ingress.kubernetes.io/rewrite-target filters[].urlRewrite.path
nginx.ingress.kubernetes.io/rate-limit Controller-specific — check your Gateway implementation

Cilium, Envoy Gateway, and Traefik all have mature Gateway API implementations. Run both Ingress and HTTPRoute objects in parallel during migration — they coexist cleanly on any properly configured controller.