The Kubernetes Gateway API defines GatewayClass, Gateway and HTTPRoute as separate resources. What does each represent, and which team normally owns each?
answer
- GatewayClass ≈ StorageClass, controllerName
- Gateway = listeners, ports, TLS, allowedRoutes
- HTTPRoute = matches, filters, weighted backendRefs
- infra provider / cluster operator / app dev
- attachment is two-sided: parentRefs + allowedRoutes
basics
~20 sGatewayClass names an implementation, like StorageClass does for volumes. Gateway is a concrete listener with ports, hostnames and TLS, created by the cluster operator. HTTPRoute holds path and header matches plus backend Services, written by app teams and attached to a Gateway.
solid answer
~50 sThe Gateway API splits what Ingress crammed into one object into three role-oriented resources. - **GatewayClass** (cluster-scoped) names an implementation via `spec.controllerName`, e.g. an Envoy- or NGINX-based controller. Installed by the infrastructure provider, exactly analogous to `StorageClass`. - **Gateway** (namespaced) asks that implementation for an actual data-plane instance. It declares `listeners`: port, protocol, optional hostname, TLS `certificateRefs`, and `allowedRoutes` controlling which namespaces and route kinds may attach. Cluster operators own it, because it owns certificates, ports and the external address. - **HTTPRoute** (namespaced) is the developer-facing object: `parentRefs` pointing at a Gateway, `hostnames`, and `rules` with matches (path, header, method, query), filters (rewrite, redirect, header modification, mirror) and weighted `backendRefs`. The payoff is RBAC that matches reality: a developer ships routing changes in their own namespace without ever being able to touch TLS or listener configuration, and the operator's Gateway stays a stable, reviewed object.
code
yaml · 29 linesapiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: prod
spec:
controllerName: example.net/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: edge
namespace: infra
spec:
gatewayClassName: prod
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- name: wildcard-example-com
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: "true"go deeper
Name the three objects and say plainly what each is for: implementation, listener, routing rules. Knowing that HTTPRoute points at Services is enough.
Be able to write all three by hand and explain the fields that matter — controllerName, listeners with TLS, parentRefs, matches and backendRefs — and say why the split exists.
Tie the model to RBAC and operations: who gets write access to what, how allowedRoutes bounds tenants, and how to read status conditions when a route silently fails to attach.
Frame it as a multi-tenancy and ownership contract: a small number of reviewed Gateways as the org's ingress surface, self-service routes bounded by policy, and portability across conformant implementations as a vendor-risk decision.
## Why three objects instead of one A Kubernetes `Ingress` object mixes concerns owned by different people. The same YAML carries the hostname, the TLS certificate reference, the choice of controller, vendor-specific annotations, and the application's path rules. In a shared cluster that forces an ugly choice: either give every application team write access to objects that control certificates and public hostnames, or funnel every routing change through the platform team. The Gateway API's central design idea is **role-oriented separation** — split the model along the lines of who actually owns each decision. ## GatewayClass `GatewayClass` is cluster-scoped and is the template/implementation selector. Its key field is `spec.controllerName`, a domain-prefixed string such as `example.net/gateway-controller`, which tells the API server-side nothing but tells each installed controller "this class is mine". It is the direct analogue of `StorageClass` for volumes or `IngressClass` for Ingress. An optional `parametersRef` points at an implementation-specific CRD or ConfigMap holding tuning knobs (instance size, logging, proxy settings). The infrastructure provider — the vendor, the cloud, or the platform team that installs the controller — owns this object. Application teams normally never create one. ## Gateway `Gateway` is namespaced and represents a *request for an actual instance of traffic-handling infrastructure*. Creating one typically causes the controller to provision or configure something real: a cloud load balancer, or a Deployment plus Service of proxy pods. Its important fields: - `gatewayClassName` — which implementation serves it. - `listeners[]` — each with a `name`, `port`, `protocol` (HTTP, HTTPS, TLS, TCP, UDP), an optional `hostname` (which may be a wildcard like `*.example.com`), a `tls` block with `mode` and `certificateRefs` pointing at Secrets, and `allowedRoutes` restricting which route kinds and which namespaces may attach. - `status` — the addresses assigned, plus conditions such as `Accepted` and `Programmed`, and per-listener `attachedRoutes` counts and `ResolvedRefs`. Cluster operators own Gateways precisely because listeners encode the things you do not want self-service: public ports, hostnames that map to real DNS, and certificate references. ## HTTPRoute `HTTPRoute` is namespaced and is what application developers write. Its shape: - `parentRefs[]` — the Gateway (or Gateways) it attaches to, optionally narrowed to one listener with `sectionName` or `port`. - `hostnames[]` — intersected with the listener's hostname; a route whose hostnames do not intersect is simply not attached. - `rules[]` — each rule is `matches` (path with `type: Exact`/`PathPrefix`/`RegularExpression`, `headers`, `queryParams`, `method`), optional `filters` (`RequestHeaderModifier`, `RequestRedirect`, `URLRewrite`, `RequestMirror`, `ExtensionRef`), and `backendRefs` — one or more Services, each with an optional `weight`. Other route kinds exist for other protocols: `GRPCRoute`, and the still-experimental `TCPRoute`, `UDPRoute` and `TLSRoute`. ## How a request flows DNS resolves the hostname to the address in the Gateway's status. The connection lands on a listener chosen by port and, for TLS, by SNI. The implementation then considers only the routes attached to that listener, picks a rule using the spec's deterministic precedence (exact path beats prefix; longer prefix beats shorter; then method match, then number of header and query matches; ties broken by oldest route and rule order), applies filters, and forwards to a backend chosen by weight. ## Why the split matters operationally Because the objects are separate, RBAC is trivial: grant developers `create/update` on `HTTPRoute` in their namespace and nothing else. Because attachment is two-sided — the route names a parent, the Gateway declares `allowedRoutes` — neither side can unilaterally hijack the other. And because status is per-resource, a developer can see `Accepted: False` on their own route with a reason like `NotAllowedByListeners` instead of guessing why traffic never arrived. ## Portability All three are CRDs installed separately from Kubernetes itself; they are not built into kube-apiserver. `GatewayClass`, `Gateway` and `HTTPRoute` reached `v1` (GA) in Gateway API 1.0. Because the core routing surface is standardised rather than expressed in vendor annotations, moving between conformant implementations is mostly a matter of changing `gatewayClassName`.
- Where do you look first when an HTTPRoute appears healthy in the app namespace but no traffic reaches the pods?Read `status.parents[]` on the HTTPRoute itself. Each parentRef gets conditions: `Accepted` tells you whether the Gateway took the route, with reasons like `NotAllowedByListeners`, `NoMatchingListenerHostname` or `NoMatchingParent`; `ResolvedRefs` tells you whether the backend Services and any referenced Secrets actually resolved. Then check the Gateway's own `Programmed` condition and per-listener `attachedRoutes` count.
- Can one HTTPRoute attach to more than one Gateway, and can several routes attach to one listener?Yes to both. `parentRefs` is a list, so the same route can be exposed on an internal and an external Gateway at once. A listener normally has many routes attached — typically one per team or service — and the implementation merges them, resolving overlaps with the spec's deterministic match precedence rather than by file order.
- How is GatewayClass different from IngressClass?Both select an implementation by controller name, and both are cluster-scoped. The difference is what sits beneath them: IngressClass is selected directly by each Ingress object, whereas GatewayClass is selected by a Gateway, and routes then attach to that Gateway. That extra level is what lets one operator-owned listener serve many independently-owned routes.
Think of an airport: GatewayClass is the airline (who operates flights), Gateway is the terminal with its numbered gates and security rules, and HTTPRoute is an individual flight's boarding assignment. Airlines and terminal operators are not the same people as the ones scheduling flights.
saying these in an interview costs you the question
- Saying Gateway API is just a renamed Ingress with nicer YAML, missing that the point is role separation and standardised routing semantics
- Claiming Gateway API is built into the Kubernetes API server — the resources are CRDs installed with an implementation
- Thinking a developer creates the Gateway; in the intended model developers create only routes
- Assuming any HTTPRoute can attach to any Gateway by naming it — the Gateway's allowedRoutes must permit it
- Confusing GatewayClass with a load balancer instance; the instance is the Gateway