Gateway API with GKE
So I have a service running in a Kubernetes cluster
and I desire to expose this service to the world. There are a host of ways to do this today:
- Create a service of type “Loadbalancer”
- Using an ingress with myriad choices of ingress controllers
- Using a mesh implementation of a gateway, for eg. the one with Istio here
The focus of this post is a new way to do this which is using Kubernetes Gateway API, which enhances the previous approaches with a more expressive spec and with a role-based separation of responsibilities:
There are a few new resource types that Gateway API introduces, each resource type managed by different roles in an organization.
A demo best clarifies these, so here it goes.
Demo Application
The codebase of the demo application is here. It is a state of the art helloworld service which returns a json response when a “/greetings” path is accessed.
I deployed this application to a Google Kubernetes Engine(GKE) based Autopilot cluster, the specs are here
Now, assuming that the pods and the service has started up cleanly, let’s start with the Gateway:
Gateway Class and Gateway
Gateway class is provided by the Infrastructure provider, in this instance Google Cloud provides the following Gateway Classes:
gke-l7-global-external-managed — Global external Application Load Balancer
gke-l7-regional-external-managed — Regional external Application Load Balancer
gke-l7-rilb — Internal Application Load Balancer(s)
And so on..
In my case I wish to expose an external HTTP endpoint, so a Cluster operator provisioning a Gateway would use a spec which looks like this:
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: external-http
spec:
gatewayClassName: gke-l7-global-external-managed
listeners:
- name: http
protocol: HTTP
port: 80
with the gatewayClassName pointing to the appropriate Gateway class name.
HttpRoute
So now that a Gateway is in place, it can route the calls to the service based on different rules:
- host name
- URL path
- Http headers
In my case, I want a simple routing based on “/greetings” path prefix and such a HttpRoute spec looks something like this:
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
name: helloworld-go-external
spec:
parentRefs:
- kind: Gateway
name: external-http
rules:
- matches:
- path:
type: PathPrefix
value: /greetings
backendRefs:
- name: helloworld-go-service
port: 8080
A few things to note here, see how there is a reference to the gateway through “parentRefs” and the rule matches on a path prefix of “/greetings”, and if it matches routes the request to the service.
That’s all there is to it, once these pieces are in place GKE should create a loadbalancer ip, route calls to “http://IP/greetings” to my service.
One small wrinkle that I saw was that the Loadbalancer NEGS pointing to the GKE pods were not in a healthy state, this is because by default a healthcheck is sent to the root path “/” which I did not have for my application, to fix this I needed to define a HealthCheckPolicy resource which looks like this:
apiVersion: networking.gke.io/v1
kind: HealthCheckPolicy
metadata:
name: helloworld-go-healthcheck
spec:
default:
config:
type: HTTP
httpHealthCheck:
port: 8080
requestPath: /greetings/health
targetRef:
group: ""
kind: Service
name: helloworld-go-service
Conclusion
Gateway API with Gateway, HttpRoute resources is a much more expressive resource and keeps the duties separated by roles. As a cluster admin I can expose a loadbalancer to my cluster and as a developer all I have to do is to create the HttpRoutes to direct the traffic to my service.