K8s Gateway API Replacing Ingress? Complete Migration Guide for Service Mesh Traffic Management in 2026

DevOps

K8s Gateway API Replacing Ingress? Complete Migration Guide for Service Mesh Traffic Management in 2026

Still writing piles of annotations on Ingress for traffic management? Scouring docs every time you configure canary deployments for the nginx.ingress.kubernetes.io/canary syntax? Tearing your hair out over cross-cluster routing with Ingress? In 2026, Kubernetes Gateway API is GA and stable — it's time to leave the Ingress chaos behind.


Background

Limitations of Ingress

Since Kubernetes 1.1, Ingress has been the standard for cluster ingress traffic management. But its design has fundamental flaws:

Dimension Ingress Gateway API
Role Model No role separation Three roles (infra ops / cluster ops / app dev)
Extensibility Annotations, controller-incompatible Native extension, standard CRDs
Protocol Support Mainly HTTP/HTTPS HTTP, gRPC, TCP, UDP, TLS
Traffic Routing Single-layer path matching Multi-layer (Gateway→Route→Backend)
Multi-Cluster Not supported Native (MultiClusterService)
Status v1 stable, no evolution GA, continuously iterating

Gateway API Core Resources

Gateway API defines three core roles and corresponding resources:

  • GatewayClass: Infrastructure admin defines gateway type (analogous to StorageClass)
  • Gateway: Cluster operator defines gateway instance (analogous to PVC)
  • HTTPRoute/TCPRoute/GRPCRoute: App developer defines routing rules (analogous to app deployment)

Problem Analysis

Why Ingress Falls Short in Service Mesh Scenarios

Root cause: Ingress couples infrastructure configuration and application routing rules in the same resource. In service mesh scenarios:

  1. Permission conflicts: Ops configure TLS certs, devs change routing rules — all on the same Ingress object
  2. Annotation hell: Canary, traffic mirroring, retry policies rely on annotations with different syntax per controller
  3. Cross-cluster blind spot: Ingress cannot discover services in other clusters; multi-cluster traffic needs external solutions
  4. Protocol limitations: gRPC, TCP long connections and other non-HTTP protocols lack full support

Step-by-Step: Migrating from Ingress to Gateway API

Step 1: Install Gateway API CRDs and Istio

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

# Install Istio 1.24+ (built-in Gateway API support)
istioctl install --set profile=ambient --set values.pilot.env.ENABLE_GATEWAY_API=true

# Verify GatewayClass is registered
kubectl get gatewayclass
# NAME              CONTROLLER                  ACCEPTED   AGE
# istio             istio.io/gateway-controller True       1m

Step 2: Define Gateway Instance

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: main-gateway
  namespace: infra
  annotations:
    istio.io/traffic-policy: |
      connectionPool:
        http:
          h2UpgradePolicy: UPGRADE
spec:
  gatewayClassName: istio
  listeners:
    - name: http
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: Selector
          selectorLabels:
            gateway-access: "true"
    - name: https
      port: 443
      protocol: HTTPS
      tls:
        mode: Terminate
        certificateRefs:
          - name: wildcard-cert
            namespace: cert-manager
      allowedRoutes:
        namespaces:
          from: All
    - name: grpc
      port: 15443
      protocol: HTTPS
      tls:
        mode: Terminate
        certificateRefs:
          - name: grpc-cert

Step 3: Migrate Routing Rules

Original Ingress config → Gateway API HTTPRoute with native weight-based canary:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-route
  namespace: app
spec:
  parentRefs:
    - name: main-gateway
      namespace: infra
      sectionName: https
  hostnames:
    - "app.example.com"
  rules:
    - backendRefs:
        - name: api-v1
          port: 8080
          weight: 80
        - name: api-v2
          port: 8080
          weight: 20
      matches:
        - path:
            type: PathPrefix
            value: /api

Step 4: Header-Based Canary Routing

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-canary-header
  namespace: app
spec:
  parentRefs:
    - name: main-gateway
      namespace: infra
  hostnames:
    - "app.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api
          headers:
            - type: Exact
              name: X-Canary
              value: "true"
      backendRefs:
        - name: api-v2
          port: 8080
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: api-v1
          port: 8080

Step 5: Multi-Cluster Gateway Configuration

apiVersion: gateway.networking.k8s.io/v1beta1
kind: ServiceImport
metadata:
  name: api-v1-multi
  namespace: app
spec:
  type: ClusterSetIP
  ports:
    - port: 8080
  resolution: DNS

---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: MultiClusterService
metadata:
  name: api-v1-global
  namespace: app
spec:
  serviceImport:
    name: api-v1-multi
    namespace: app
  clusterBackends:
    - cluster: us-west-1
      weight: 60
    - cluster: us-east-1
      weight: 40

Complete Code: Istio + Gateway API Production Configuration

# gateway-class.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: istio-production
spec:
  controllerName: istio.io/gateway-controller
  parametersRef:
    group: ""
    kind: ConfigMap
    name: istio-gw-params
    namespace: infra

---
# gateway-params.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: istio-gw-params
  namespace: infra
data:
  concurrency: "4"
  proxy-config: |
    connectionPool:
      http:
        maxRequestsPerConnection: 1000
        h2UpgradePolicy: DEFAULT
      tcp:
        maxConnections: 10000
    outlierDetection:
      consecutive5xxErrors: 5
      interval: 30s
      baseEjectionTime: 30s

---
# gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-gateway
  namespace: infra
spec:
  gatewayClassName: istio-production
  listeners:
    - name: http-public
      port: 80
      protocol: HTTP
      allowedRoutes:
        namespaces:
          from: All
    - name: https-public
      port: 443
      protocol: HTTPS
      tls:
        mode: Terminate
        certificateRefs:
          - name: prod-wildcard-cert
      allowedRoutes:
        namespaces:
          from: All
  addresses:
    - type: IPAddress
      value: "10.0.1.100"

---
# http-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: app-route
  namespace: app
spec:
  parentRefs:
    - name: prod-gateway
      namespace: infra
      sectionName: https-public
  hostnames:
    - "app.example.com"
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /api/v2
          headers:
            - type: Exact
              name: X-Canary
              value: "true"
      filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            add:
              - name: X-Route-Tag
                value: canary-v2
      backendRefs:
        - name: api-v2
          port: 8080
          weight: 100
    - matches:
        - path:
            type: PathPrefix
            value: /api/v2
      backendRefs:
        - name: api-v2
          port: 8080
          weight: 20
        - name: api-v1
          port: 8080
          weight: 80
    - matches:
        - path:
            type: PathPrefix
            value: /api
      backendRefs:
        - name: api-v1
          port: 8080
    - matches:
        - path:
            type: PathPrefix
            value: /health
      backendRefs:
        - name: api-v1
          port: 8080
      filters:
        - type: RequestHeaderModifier
          requestHeaderModifier:
            set:
              - name: X-Health-Check
                value: "true"

---
# grpc-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
  name: grpc-route
  namespace: app
spec:
  parentRefs:
    - name: prod-gateway
      namespace: infra
  hostnames:
    - "grpc.example.com"
  rules:
    - matches:
        - method:
            service: "com.example.api.UserService"
            method: "GetUser"
      backendRefs:
        - name: user-service
          port: 9090
    - matches:
        - method:
            service: "com.example.api.OrderService"
      backendRefs:
        - name: order-service
          port: 9090

Pitfall Guide

Pitfall 1: GatewayClass Not Registered

Symptom: Gateway shows Accepted: False, routes don't take effect.

Fix: Verify Istio controller has Gateway API enabled, check ENABLE_GATEWAY_API=true, ensure GatewayClass controllerName matches Istio's registration.

Pitfall 2: Cross-Namespace Routes Rejected

Symptom: HTTPRoute's parentRefs references a Gateway in another namespace, but routing doesn't work.

Fix: Gateway's allowedRoutes must explicitly allow cross-namespace routing. Set from: All or use Selector with matching labels.

Pitfall 3: TLS Certificate Cross-Namespace Reference Fails

Symptom: Gateway's HTTPS listener references a certificate in another namespace.

Fix: Gateway API requires certificates in the same namespace. Use cert-manager to replicate certificates, or use Istio's istio.io/credential-name annotation.

Pitfall 4: Canary Weights Don't Sum to 100

Symptom: Configuring weight 80 and 30 (total 110) causes unexpected traffic distribution.

Fix: Gateway API weights are relative and don't need to sum to 100. However, keeping the total at 100 is recommended for clarity. Istio normalizes automatically.

Pitfall 5: Multi-Cluster ServiceImport DNS Resolution Fails

Symptom: MultiClusterService created but cross-cluster traffic can't route.

Fix: Ensure Istio cross-cluster control plane is connected (east-west gateway deployed), check ServiceImport resolution is DNS, and verify inter-cluster network reachability.


Error Troubleshooting

# Error Message Cause Solution
1 GatewayClass not found CRDs not installed or controller not registered Install Gateway API CRDs, confirm Istio Gateway API enabled
2 no GatewayClass controller matching controllerName mismatch Check GatewayClass.spec.controllerName matches Istio registration
3 route is not accepted by any Gateway parentRefs reference error Check Gateway name, namespace, sectionName
4 certificate not found TLS cert missing or cross-namespace Ensure cert in same namespace as Gateway
5 port conflict on Gateway listener Multiple listeners on same port Only one listener per port, merge protocol config
6 backendRef service not found Target Service doesn't exist Check Service name and namespace
7 HTTPRoute condition Accepted=False Route rejected by Gateway Check allowedRoutes policy and hostname matching
8 Istio proxy not ready Sidecar/ztunnel not injected Confirm istio-injection=enabled label or ambient mode
9 MultiClusterService endpoint empty Cross-cluster discovery not working Check east-west gateway, control plane connectivity
10 GRPCRoute method match failed gRPC method format error Use package.Service/Method format

Advanced Optimization

1. Traffic Mirroring (Shadow Traffic)

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: mirror-route
  namespace: app
  annotations:
    istio.io/traffic-mirror: |
      mirror:
        hostname: mirror-service
        port: 8080
      mirrorPercentage:
        value: 10
spec:
  parentRefs:
    - name: prod-gateway
      namespace: infra
  rules:
    - backendRefs:
        - name: api-v1
          port: 8080

2. Connection Pool and Circuit Breaker

Configure global connection pool policies via GatewayClass parametersRef ConfigMap to prevent single backend overload.

3. Error-Rate Based Auto Traffic Shifting

Combine Prometheus metrics with Argo Rollouts for automatic traffic shifting based on error rates.

4. Gateway API Extension Policies

Use policyRef (v1.3+) to decouple retry, timeout, and circuit breaker policies from routes.


Comparison

Dimension Ingress + nginx-ingress Ingress + Istio VS Gateway API + Istio Gateway API + Envoy GW
Config Complexity Low (single resource) Medium (Ingress+VS) Medium (Gateway+Route) Medium (Gateway+Route)
Role Separation None Partial Complete Complete
Canary Deployment Annotations VirtualService Native weight Native weight
gRPC Support Limited annotations Native Native GRPCRoute Native GRPCRoute
Multi-Cluster Not supported Supported (needs config) Native Needs extension
Traffic Mirroring Not supported Supported Annotation extension Extension policy
Community Activity Maintenance mode Active Very active Active
Learning Curve Low High Medium Medium
Production Readiness Mature Mature 2026 GA mature Rapidly maturing

Summary

Summary: Gateway API has become the de facto standard for Kubernetes traffic management in 2026. Compared to Ingress, it provides role separation, protocol extensibility, and multi-cluster support. The migration path is clear: install CRDs, create Gateway, then migrate Routes. Istio provides the most mature Gateway API support. New projects should use Gateway API directly; existing projects can migrate service by service — Ingress and Gateway API can coexist.


Try these browser-local tools — no sign-up required →

#Kubernetes#Gateway API#服务网格#Istio#Envoy#流量管理#API网关#云原生