Konrad Kowalski (rootsher)Principal Platform & Reliability Architect100110110011000111101000110001000001101010110011

From Service to Gateway API: Where the Problem Came From

date
category
Networking
also in
Containers
reading
1 min / 284 words

At first, the problem was simple:

text
I have a Service
I want to reach it from outside the cluster

Service type: LoadBalancer fits that model.

yaml
apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

That is a good API if you are thinking about a port and a backend.

HTTP quickly adds questions that Service does not try to answer:

text
which host?
which path?
where does TLS terminate?
what about redirects?
what about rewrites?
what about timeouts?

That is why Ingress appeared.

Ingress named only part of the problem

The simplest Ingress looks reasonable.

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

The contract is clear:

text
example.com/
  -> Service web:80

The problem starts with the next requirement.

yaml
metadata:
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/proxy-read-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-body-size: "20m"

Formally, we are still looking at Ingress.

In practice, we are looking at ingress-nginx configuration.

Annotations were a signal

Annotations were not random mess.

They were a way to add features that Ingress could not express.

Production needed:

text
redirects
rewrites
timeouts
body limits
header manipulation
canary traffic
custom authorization

The Ingress specification was smaller than the real problem.

Controllers filled that gap in their own ways.

That worked until you needed to change controllers or standardize a cluster.

Then the portable Kubernetes resource turned out to contain a non-portable part:

text
nginx.ingress.kubernetes.io/*

Gateway API splits the roles

Gateway API is not one new proxy.

It is a resource model that separates things previously packed into Ingress.

text
GatewayClass
  |
  v
Gateway
  |
  v
HTTPRoute
  |
  v
Service

GatewayClass says which controller and which kind of infrastructure will handle Gateways.

Gateway says where traffic enters: port, protocol, host, TLS, allowed routes.

HTTPRoute says how HTTP traffic reaches services.

That matters more than the YAML shape itself.

Ingress mixed a platform decision and an application route into one resource.

Gateway API tries to separate those decisions.

The platform can manage:

text
GatewayClass
Gateway
listeners
TLS defaults
allowed namespaces

The application can manage:

text
hostnames
paths
headers
backendRefs
traffic splitting

What really changes

This is not about:

text
Ingress is old
Gateway API is new

It is about Ingress having too little language.

Gateway API adds names for things that already existed in clusters:

text
who provides the load balancer
where TLS terminates
who may attach a route to a listener
which team controls application routing
which behavior is standard
which behavior depends on an implementation

It does not remove the need to understand the controller.

But it moves more of the contract out of annotations and into the API.