Konrad Kowalski (rootsher)Principal Platform & Reliability Architect111110111001100101011011101010100001111100001001

GatewayClass: A Contract With the Implementation

date
category
Networking
also in
Containers
reading
2 min / 335 words

GatewayClass is easy to mistake for a label.

yaml
gatewayClassName: public

It looks like:

text
use the public gateway

But GatewayClass is more important than that.

It is the resource that says which controller handles a class of Gateways.

Minimal model

The relationship looks like this:

text
GatewayClass
  |
  v
Gateway
  |
  v
HTTPRoute

HTTPRoute attaches to Gateway.

Gateway points to GatewayClass.

GatewayClass points to the implementation through controllerName.

Example:

yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: public
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller

This does not create a traffic entry point yet.

It says:

text
Gateways with gatewayClassName: public
are handled by the Envoy Gateway controller

GatewayClass belongs to the platform

An application team usually should not create its own GatewayClass.

This is a platform decision:

text
which implementations do we allow?
which ones are public?
which ones are private?
which ones have Internet access?
which ones are internal only?
which ones have shared security policies?

A small cluster may have one class:

text
public

A larger environment may have separate classes:

text
public
internal
mesh
edge
regional

Those names are not part of the standard. The standard defines the mechanism, not the organization's vocabulary.

A class does not guarantee identical features everywhere

Gateway API is a specification.

The implementation decides how it handles a feature and which extensions it exposes.

So two classes can look similar:

text
public-nginx
public-envoy

but differ in behavior:

text
regex path matching
timeouts
body size
header manipulation
TLS options
observability
custom filters

With Ingress, these differences often hid in annotations.

With Gateway API, they should be more visible: through standard fields, policies, or implementation extensions.

Practical GatewayClass types

There are no official GatewayClass kinds like:

text
PublicGatewayClass
PrivateGatewayClass
MeshGatewayClass

There is one GatewayClass resource.

The types come from platform decisions.

Example split:

text
public
  Internet-facing entry point
  TLS required
  restricted namespaces

internal
  private-network entry point
  no public address
  different DNS rules

mesh
  service mesh integration
  service identity policies

experimental
  new implementation
  no production traffic

That is the role of GatewayClass: name an allowed variant of infrastructure.

Not per application.

Per way of delivering traffic.

Why this matters in migration

During an ingress-nginx migration, it is tempting to start with:

text
how do I rewrite Ingress as HTTPRoute?

That is too late.

First you need to know:

text
which GatewayClass replaces ingressClassName: nginx?

If the old object had:

yaml
spec:
  ingressClassName: nginx

the new model needs an answer:

yaml
spec:
  gatewayClassName: public

or:

yaml
spec:
  gatewayClassName: nginx

or something else, depending on the implementation and platform policy.

That is not cosmetic naming.

It decides which controller programs the real traffic path.

A good class name tells the truth

Weak name:

text
gateway

Better name:

text
public
internal
edge
mesh

Even better if the organization has several implementations:

text
public-envoy
internal-nginx
mesh-istio

The name should help an application team choose the correct variant without reading implementation details.

But it should not pretend the implementation does not exist.

It always comes back during debugging:

text
manifest
  |
  v
controller
  |
  v
proxy or cloud load balancer
  |
  v
request

GatewayClass is where that chain becomes concrete.