The Gateway API

How GatewayClass, Gateway and HTTPRoute share the work of an Ingress, and how to write matches and traffic splits.

40 min 2 hands-on tasksNetworking · 20% of the exam

Key ideas in this lesson · tap one for a simple explanation

What you will be able to do

  • Say which team owns GatewayClass, Gateway and HTTPRoute, and how a route attaches to a listener.
  • Write an HTTPRoute with hostnames, path matches and weighted backends, and check it with kubectl.
  • Turn an Ingress into a Gateway plus an HTTPRoute, including TLS.

The is the newer way to let web traffic into a cluster. It does the job of an , with more features, and splits the work over three objects. The exam topic is Use the Gateway API to manage Ingress traffic. A typical task: create a Gateway and an HTTPRoute, split traffic between two versions, or turn an Ingress into Gateway API objects.

It is all , because there is no kubectl create gateway. So you need a clear picture of the three objects, and a fast way to look up their fields.

Why it exists

An Ingress puts everything in one object: the entry point, TLS and every route. Anything beyond host and path, such as redirects or traffic splits, went into annotations. Each controller had its own annotations, so they did not work across controllers. The Gateway API (gateway.networking.k8s.io/v1) splits the object by team, and puts those features into the spec itself.

Three objects, three owners

KindScopeOwned bySays
GatewayClassThe whole clusterThe infrastructure team"Gateways of this class are run by controller X" (spec.controllerName)
GatewayOne The cluster operator"Listen on these ports and hostnames, with these certificates, and accept routes from these namespaces"
HTTPRouteOne namespaceThe app team"For these hostnames and paths, send traffic to these " (parentRefs picks the Gateway)
How the objects connect

GatewayClass

which controller runs the Gateways

nw-edge

Gateway

listeners: ports and hostnames

edge

HTTPRoute

rules: host and path to a Service

store

Service

your app's Pods

store-v1

Each object names the one before it: the Gateway names its class, and the route names its Gateway in parentRefs.

Like an Ingress, none of this moves any traffic by itself:

  • A controller does the work. It reads the objects and runs the actual proxy.
  • This lab installs the Gateway API but no controller. Your objects are checked and saved, but their status stays at Waiting for controller, and no traffic flows.
  • On the exam, a controller is installed, and the grader can send real requests.

These commands show what is installed, and which fields each kind has:

Terminal
kubectl get crd | grep gateway.networking.k8s.io
kubectl api-resources --api-group=gateway.networking.k8s.io
kubectl get gatewayclass                       # which controllers exist (exam: usually one)
kubectl get gateway,httproute -A

# The CRDs carry full schemas, so kubectl explain works offline and is faster than the docs
kubectl explain gateway.spec.listeners
kubectl explain httproute.spec.rules.backendRefs
kubectl explain httproute.spec.rules.filters --recursive | less

GatewayClass and Gateway

The Gateway is the entry point. Each listener on it is one port and protocol, and optionally one hostname. This one has two listeners: HTTP on port 80, and HTTPS on port 443 for one host.

A class and a Gateway with two listeners
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: nw-edge
spec:
  controllerName: example.com/gateway-controller   # must match the installed controller; immutable
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: edge
  namespace: nw-gw
spec:
  gatewayClassName: nw-edge
  listeners:
    - name: http                 # routes can target one listener with parentRefs[].sectionName
      protocol: HTTP
      port: 80
      allowedRoutes:
        namespaces:
          from: Same             # the default; All, or Selector with a label selector
    - name: https
      protocol: HTTPS
      port: 443
      hostname: "store.nw.local" # optional; routes must share a hostname with the listener
      tls:
        mode: Terminate          # the default for HTTPS
        certificateRefs:
          - kind: Secret
            name: store-tls      # kubernetes.io/tls Secret in the Gateway's namespace

allowedRoutes says which routes may attach to a listener. The default, from: Same, allows only routes in the Gateway's own namespace. To let routes from other namespaces attach, use from: All, or from: Selector with a namespace .

HTTPRoute

The HTTPRoute holds the routing rules. This one sends store.nw.local/store to two versions of an app: 80% to store-v1 and 20% to store-v2. That is a traffic split, often used to try a new version on a few users first.

Hostname, path match and an 80/20 split
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: store
  namespace: nw-gw
spec:
  parentRefs:
    - name: edge                 # the Gateway; add sectionName: http to pin one listener
  hostnames:
    - store.nw.local
  rules:
    - matches:
        - path:
            type: PathPrefix     # Exact, PathPrefix, or RegularExpression (controller-dependent)
            value: /store
      backendRefs:
        - name: store-v1         # a Service in the route's namespace
          port: 80               # Service port; required for Services
          weight: 80
        - name: store-v2
          port: 80
          weight: 20             # weights are relative: 4 and 1 would split the same way
  • matches: a request needs to match only one entry of the list. Inside one entry, every field (path, headers, method, …) must match. A rule with no matches catches every path.
  • backendRefs: weight is 1 when you leave it out, and a weight of 0 sends nothing. A Service in another namespace also needs a ReferenceGrant there: an object that allows the reference.
  • Which rule wins: the most specific match. For example, an Exact path beats a prefix, and a longer prefix beats a shorter one.

Filters

A filter changes a request on its way through. The most common one is a redirect, for example from an old path to a new one:

A redirect filter
  rules:
    - matches:
        - path: { type: PathPrefix, value: /old-shop }
      filters:
        - type: RequestRedirect          # answers the client itself; no backendRefs allowed in this rule
          requestRedirect:
            path:
              type: ReplacePrefixMatch
              replacePrefixMatch: /store
            statusCode: 301

Other filters work the same way. URLRewrite changes the path on its way to the backend. RequestHeaderModifier and ResponseHeaderModifier edit headers. RequestMirror copies each request to a second backend. kubectl explain httproute.spec.rules.filters lists all their fields.

From Ingress to Gateway API

Every Ingress field has a place in the Gateway API. Use this table when a task asks you to move an Ingress over:

IngressGateway API
ingressClassName and IngressClassgatewayClassName and GatewayClass
The controller's Service and its portsGateway.spec.listeners
spec.tls[].secretNamelisteners[].tls.certificateRefs, on the Gateway
rules[].hostHTTPRoute.spec.hostnames
pathType: Prefix / Exactpath.type: PathPrefix / Exact
backend.service.port.numberbackendRefs[].port
Annotations (rewrite, redirect, canary)filters and weight, in the spec

In the official docs· open on exam day too

Hands-on task 1 of 2nw-gw-1
~8 min6% weightNetworking

A Gateway with a weighted HTTPRoute

Create a GatewayClass named nw-edge whose controller name is example.com/gateway-controller. In namespace nw-gw, create a Gateway named edge of that class with one listener named http for protocol HTTP on port 80 that accepts routes from its own namespace only. Then create an HTTPRoute named store attached to edge for hostname store.nw.local. Requests whose path starts with /store must be split so that 80% go to Service store-v1 and 20% to Service store-v2, both on port 80. (The Services exist; their Pods and a Gateway controller are not needed for this task.)

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/nw-gw-1/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/nw-gw-1/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/nw-gw-1/cleanup | bash
Hands-on task 2 of 2nw-gw-2
~10 min7% weightNetworking

Migrate an Ingress to the Gateway API

The Ingress legacy in namespace nw-gw2 must be replaced by Gateway API objects. Using the existing GatewayClass nw-lab, create a Gateway named legacy-gw in nw-gw2 with a listener named https on port 443 using protocol HTTPS for hostname legacy.nw.local, terminating TLS with the Secret the Ingress uses. Then create an HTTPRoute named legacy attached to that Gateway that reproduces the Ingress's host and path routing exactly. Leave the Ingress in place.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/nw-gw-2/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/nw-gw-2/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/nw-gw-2/cleanup | bash

Finished this lesson?

0 of 2 tasks passed. Your readiness counts tasks, so run them before you move on.