skip to content

Gateway API Overview

The Gateway API is Ingress's successor, splitting concerns across GatewayClass, Gateway and HTTPRoute so infrastructure and application teams own different layers. Increasingly asked as a 'what is replacing Ingress and why' question.

part ofKubernetesoverview, primer and where to startread it →
on this pageshow

questions

4

The Kubernetes Gateway API defines GatewayClass, Gateway and HTTPRoute as separate resources. What does each represent, and which team normally owns each?

level: middleimportance: must knowfreq 52%

answer

  1. GatewayClass ≈ StorageClass, controllerName
  2. Gateway = listeners, ports, TLS, allowedRoutes
  3. HTTPRoute = matches, filters, weighted backendRefs
  4. infra provider / cluster operator / app dev
  5. attachment is two-sided: parentRefs + allowedRoutes

basics

~20 s

GatewayClass 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 s

The 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 lines
yaml
apiVersion: 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

for a junior

Name the three objects and say plainly what each is for: implementation, listener, routing rules. Knowing that HTTPRoute points at Services is enough.

for a middle

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.

for a senior

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.

for a principal

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

context

open as a page

What shortcomings of the Kubernetes Ingress resource is the Gateway API designed to fix?

level: middleimportance: must knowfreq 50%

basics

~20 s

Ingress can only express host and path rules, so everything else — rewrites, canary weights, header matching, timeouts — became vendor annotations that are untyped and unportable. It also has no role separation and only supports HTTP. Gateway API makes those first-class, typed, and role-split.

open as a page

Using the Kubernetes Gateway API, how would you send 10% of production traffic to a canary version of a service while also allowing testers to reach that canary deterministically by sending a specific request header?

level: middleimportance: should knowfreq 38%

basics

~20 s

One HTTPRoute with two rules. The first rule matches the tester header and sends 100% to the canary Service. The second, catch-all rule lists both Services in backendRefs with weights 90 and 10. Header matches take precedence over the plain path rule.

open as a page

In a multi-tenant Kubernetes cluster using the Gateway API, how does an HTTPRoute in one namespace get attached to a Gateway in another, and what controls does the cluster operator have over which namespaces are allowed to attach?

level: seniorimportance: should knowfreq 34%

basics

~20 s

Attachment is two-sided. The route names the Gateway in parentRefs (with its namespace); the Gateway's listener declares allowedRoutes.namespaces as Same, All, or Selector plus permitted route kinds. Both must agree, and hostnames must intersect, or the route's status shows it was not accepted.

open as a page