K8s Gateway API: Ingress Evolved

devops kubernetes

Kubernetes Ingress served us well, but its limitations are real. The Gateway API is the evolution—more expressive, more portable, more powerful. It’s now GA and ready for production.

The Problem with Ingress

Ingress was designed for simple HTTP routing:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend:
          service:
            name: api-service
            port:
              number: 80

Limitations:

Gateway API Architecture

┌─────────────────┐
│   GatewayClass  │  ← Infrastructure provider config
└────────┬────────┘

┌────────▼────────┐
│     Gateway     │  ← Listener configuration (ports, TLS)
└────────┬────────┘

┌────────▼────────┐
│   HTTPRoute     │  ← Routing rules
│   GRPCRoute     │
│   TCPRoute      │
│   TLSRoute      │
└─────────────────┘

Core Concepts

GatewayClass

Defines the controller:

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

Think of it as the “CSI driver” for networking.

Gateway

The actual load balancer:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: production
spec:
  gatewayClassName: istio
  listeners:
  - name: https
    port: 443
    protocol: HTTPS
    tls:
      certificateRefs:
      - name: prod-cert
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            gateway: production

HTTPRoute

The routing rules:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: api-routes
spec:
  parentRefs:
  - name: production
  hostnames:
  - api.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /v1
    backendRefs:
    - name: api-v1
      port: 80
  - matches:
    - path:
        type: PathPrefix
        value: /v2
    backendRefs:
    - name: api-v2
      port: 80

Advanced Features

Traffic Splitting

Canary deployments natively:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
spec:
  rules:
  - backendRefs:
    - name: api-v1
      port: 80
      weight: 90
    - name: api-v2
      port: 80
      weight: 10

Header-Based Routing

rules:
- matches:
  - headers:
    - name: x-api-version
      value: beta
  backendRefs:
  - name: api-beta
    port: 80

Request Modification

rules:
- filters:
  - type: RequestHeaderModifier
    requestHeaderModifier:
      add:
      - name: X-Custom-Header
        value: added-by-gateway
      remove:
      - X-Debug-Header
  backendRefs:
  - name: backend
    port: 80

Redirects

rules:
- matches:
  - path:
      type: Exact
      value: /old-path
  filters:
  - type: RequestRedirect
    requestRedirect:
      path:
        type: ReplaceFullPath
        replaceFullPath: /new-path
      statusCode: 301

Role-Based Access

Gateway API separates concerns:

RoleResourcesTypical Owner
InfrastructureGatewayClassPlatform team
Cluster OpsGatewaySRE/Ops
App DeveloperHTTPRouteDev teams

Developers can create routes without touching Gateway config.

Cross-Namespace References

# In app-namespace
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app
  namespace: app-namespace
spec:
  parentRefs:
  - name: production
    namespace: gateway-namespace  # Different namespace

With proper RBAC, teams manage their own routes.

TCP and gRPC

Not just HTTP:

# TCP routing
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
spec:
  parentRefs:
  - name: tcp-gateway
  rules:
  - backendRefs:
    - name: postgres
      port: 5432

# gRPC routing
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
spec:
  parentRefs:
  - name: production
  rules:
  - matches:
    - method:
        service: myservice.MyService
        method: MyMethod
    backendRefs:
    - name: grpc-service
      port: 50051

Migration from Ingress

Step 1: Install Gateway Controller

Choose your implementation:

Step 2: Create GatewayClass and Gateway

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: main
spec:
  gatewayClassName: your-provider
  listeners:
  - name: http
    port: 80
    protocol: HTTP

Step 3: Convert Ingress to HTTPRoute

# Before: Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app
            port:
              number: 80

# After: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app
spec:
  parentRefs:
  - name: main
  hostnames:
  - app.example.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: my-app
      port: 80

Step 4: Gradual Rollover

Run both in parallel. Switch DNS. Remove Ingress.

Should You Migrate?

Migrate now if:

Wait if:

Final Thoughts

Gateway API is the future of Kubernetes networking. It’s more expressive, more portable, and better designed than Ingress.

Start learning it now. Migrate when your controller supports it. Enjoy the cleaner abstractions.


Better APIs make better platforms.

All posts