Having introduced the Gateway API in part one of this series, we will now explore some Gateway API types and field specifications, and how they all fit together.
Installing the Gateway API Addon
You might be wondering, “Why don’t I see Gateway API resources on my Kubernetes cluster?” or “Which Kubernetes cluster version includes the Gateway API?” The answer is — you will need to install the Gateway API custom resource definitions (CRDs) yourself!
Although the Gateway API provides external traffic routing similar to Kubernetes’ built-in Ingress, its scope is much broader and is maintained separately from the core Kubernetes project. This allows the Gateway API project to be developed independently of the Kubernetes version. For this reason, Gateway API is classified as a Kubernetes addon and can be installed by following the official guide.
# example installation command
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml
Note that there are different “channels” (flavors) of Gateway API installations: standard and experimental. Which version to choose will depend on your needs. For production use, I would recommend the standard channel.
Another alternative is install a Gateway API controller of your choice, since many controllers also bundle the Gateway API CRDs in the same software package.
Basic Building Blocks
GatewayClass
The first resource we will talk about is the GatewayClass
. This resource is an abstraction of a Gateway API controller. A Gateway
resource specifies a GatewayClass
to use. This allows multiple Gateway API controllers to run on a single cluster. If you’ve been working with Kubernetes for a while, you’re likely familiar with StorageClass
and IngressClass
, which follow a similar concept.
The following GatewayClass
example defines a Gateway API controller implemented with the HAProxy Ingress controller:
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: GatewayClass
metadata:
namespace: default
name: haproxy-ingress-gatewayclass
spec:
controllerName: haproxy.org/gateway-controller
A GatewayClass
implemented with the Traefik Proxy would look like this:
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: traefik
spec:
controllerName: traefik.io/gateway-controller
Gateway
Once a GatewayClass
resource is created, we can proceed to create a Gateway
, which is the foundational object upon which all other components are built. It usually represents a load balancer or the mechanism through which incoming traffic enters the Kubernetes cluster.
Here is an example referencing the Traefik Proxy GatewayClass
we defined earlier:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: traefik
namespace: default
spec:
gatewayClassName: traefik
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- name: secret-tls
namespace: default
allowedRoutes:
namespaces:
from: All
- name: tcp
protocol: TCP
port: 3000
allowedRoutes:
namespaces:
from: Same
This example shows just few of the many configuration options available. Note, however, that unlike an Ingress resources, no routes are defined in a Gateway
. Routes are defined using a separate route resource, such as HTTPRoute
or TCPRoute
.
In the example above, the listeners entries define an (optional) allowedRoutes
, which defines which namespaces are allowed to attach routes to the Gateway
. Some listeners allow routes from any namespace (“All“) while others require the route to be in the same namespace as the Gateway
(“Same“).
HTTPRoute
An HTTPRoute
, as you might have guessed, describes the routing for requests to backend services. The are other route types, including TCPRoute, TLSRoute and UDPRoute.
An example route associated with a Traefik Proxy Gateway
:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: example-http
namespace: default
spec:
parentRefs:
- name: traefik
sectionName: http
kind: Gateway
hostnames:
- example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: example-app
namespace: default
port: 80
A Route resource can reference the parent Gateway
using the ParentRefs
attribute, or other methods such as using label selectors with the allowedRoutes
attribute on the gateway. A route will only be attached to the Gateway
, however, if it is allowed — the default behavior requiring the route and gateway to be in the same namespace.
A Route can also specify which listener to associate the route with by referring to the name (with sectionName
) or port (with port
):
# refer to a listener by name
spec:
parentRefs:
- name: traefik
sectionName: http
kind: Gateway
# refer to a listener by port
spec:
parentRefs:
- name: traefik
port: 80
kind: Gateway
An HTTPRoute
can match against a set of hostnames and are matched before any routes. Optionally, hostnames can also be defined for a listener in the Gateway
resource. However, if they are defined both in an HTTPRoute
and Gateway
, you will need to make sure that both hostname definitions match for the route to work correctly. See the official HTTPRoute spec for more details.
Advanced Features
I decided to call this section “Advanced Features” because now we’ll be exploring some of capabilities that extend beyond those offered by the Ingress resource.
Request Header Matching
A very useful feature is the ability of an HTTPRoute
is to route traffic to backends based on request headers. This feature can be used to perform a canary release, sending some traffic to a separate backed if a certain request header is matched.
In this example, if the header canary has the value “yes”, it will be matched first and routed to the app-svc-canary
backend. All other traffic will be directed to the app-svc
default backend:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
spec:
parentRefs:
- name: example-gateway
hostnames:
- "bar.example.com"
rules:
- matches:
- headers:
- type: Exact
name: canary
value: yes
backendRefs:
- name: app-svc-canary
port: 8080
- backendRefs:
- name: app-svc
port: 8080
Redirects and Rewrites
Redirects are very commonly used for redirecting traffic from HTTP to HTTPS. In an HTTPRoute, filters
are used to configure the redirect status code:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-filter-redirect
spec:
parentRefs:
- name: redirect-gateway
sectionName: http
hostnames:
- redirect.example
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
For this redirect to work, you will need to have a Gateway with listeners on HTTP (port 80) and HTTPS (port 443).
It is also possible to redirect entire paths or parts of a path, also using the filter attribute.
TLS / HTTPS Handling
With Gateway API, TLS configuration of downstream (connection to client) and upstream connections (to backend) are managed independently. You choose from various strategies:
- Pass encypted traffic to the backend (TLS passthrough)
- Terminate HTTPS traffic at the Gateway
- Terminate HTTPS and then re-encrypted upstream traffic at the Gateway
More examples can be found on the official Gateway API docs
Traffic Splitting
This is a feature I really wish existed in the Ingress API. To implement weighted traffic with the AWS Load Balancer Controller, you needed to use an ugly annotation syntax. This is a prime example of why using annotations to extend functionality breaks portability and is burdensome for the user.
A typical Ingress with weighted target groups with the AWS Load Balancer Controller using annotations:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: default
name: ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/actions.forward-multiple-tg: >
{"type":"forward","forwardConfig":{"targetGroups":[{"serviceName":"service-1","servicePort":"http","weight":20},{"serviceName":"service-2","servicePort":80,"weight":20},{"targetGroupARN":"arn-of-your-non-k8s-target-group","weight":60}],"targetGroupStickinessConfig":{"enabled":true,"durationSeconds":200}}}
...
I don’t know about you, but that’s very hard to read. No thanks!
This is how weighted backend traffic looks like in Gateway API:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: simple-split
spec:
rules:
- backendRefs:
- name: foo-v1
port: 8080
weight: 80
- name: foo-v2
port: 8080
weight: 20
Much cleaner, and vendor agnostic.
Conclusion
These are just some of the basic types and features available with the Gateway API. It’s impossible to cover all the features in one article. You can find more guides, examples and API documentation on the official gateway api docs.
The extensibility of the API almost guarantees there will be some vendor-specific additions. It will be very interesting to see more real use-cases and software developer around the Gateway API in the future.
For now, I hope this article demystifies the Gateway API and helps you get started experimenting with it.