Replacing Ingress with Gateway API (Kubernetes)

A practical migration from Ingress to Gateway API: CRDs, GatewayClass, Gateway, HTTPRoute and a checklist.

The Kubernetes Gateway API replaces the older Ingress model with a more expressive, role-oriented API. In practice it improves routing semantics, clarifies ownership, and enables controlled cross-namespace relationships.

This guide keeps the migration incremental: run in parallel with existing Ingress first, then convert host/path rules in small batches.

Gateway API CRD relationships

Gateway API CRD relationships

In short:

  • GatewayClass defines which controller implements Gateways.
  • Gateway is your entry point: listeners, (TLS) termination and policy.
  • HTTPRoute replaces Ingress host/path rules and attaches to a Gateway via parentRefs.
  • ReferenceGrant is required for cross-namespace references.

1) Install Gateway API CRDs

This is non-destructive: existing Ingress traffic continues to work.

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml
kubectl get crd | grep gateway.networking.k8s.io

Expected CRDs:

gatewayclasses.gateway.networking.k8s.io
gateways.gateway.networking.k8s.io
httproutes.gateway.networking.k8s.io
referencegrants.gateway.networking.k8s.io

2) Define a GatewayClass

GatewayClass is conceptually the successor of IngressClass. Keep it explicit.

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

If you use a different controller (Envoy, HAProxy, cloud LB controller), only controllerName changes.

3) Create a Gateway (listeners, TLS later)

Start with HTTP. Add TLS once routes are attached and verified.

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: edge-gateway
  namespace: edge
spec:
  gatewayClassName: nginx-gateway
  listeners:
    - name: http
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: All

4) Convert an Ingress to an HTTPRoute

The host/path logic remains familiar, but the attachment to the Gateway is via parentRefs.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-route
  namespace: app
spec:
  parentRefs:
    - name: edge-gateway
      namespace: edge
  hostnames:
    - app.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /
      backendRefs:
        - name: app-service
          port: 80

5) Validate status and traffic

Confirm the Gateway is ready and the route is attached. Only then switch DNS or edge/LB config.

kubectl get gateway -n edge
kubectl get httproute -n app

Example output:

NAME           CLASS          ADDRESS       PROGRAMMED   AGE
edge-gateway   nginx-gateway  203.0.113.10   True         2m

NAME        HOSTNAMES           AGE
app-route   app.example.com     2m

Migration checklist

  • Install Gateway API CRDs and your controller in parallel with Ingress.
  • Create a GatewayClass and a Gateway per environment.
  • Convert Ingress rules into HTTPRoute in small batches (per host/path).
  • Shift DNS/traffic incrementally (canary if possible).
  • Remove legacy Ingress only after traffic is stable and observability stays green.