DEV Community

Cover image for Testing out Gateway API using Gloo Gateway
Leon Nunes
Leon Nunes

Posted on

Testing out Gateway API using Gloo Gateway

Hey folks, been a while, I've been hearing a lot about the Gateway API for the past few months and it seems like the defacto for gateways now.

Since we also implemented the Gateway API I thought why not test it out!

So today I'll be testing Gloo Gateway which is an opensource API-Gateway based on the extremely performant envoy proxy. Our documentation takes you through this, but I'm going to also do something similar.

To begin with we need to make sure we have the Kubernetes Gateway CR's in our cluster.

kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.2.0/standard-install.yaml 
Enter fullscreen mode Exit fullscreen mode

You can use the above command to install it in your cluster. I use Talos to setup k8s on my end. You can also create a sample Talos cluster using docker.

Moving on we are going to use Helm to test things out. Here we're adding the Gloo Open Source Repository.

helm repo add gloo https://storage.googleapis.com/solo-public-helm helm repo update 
Enter fullscreen mode Exit fullscreen mode

Then we can install the helm chart using

helm install -n gloo-system gloo gloo/gloo \ --create-namespace \ --version 1.18.13 \ -f -<<EOF discovery: enabled: false gatewayProxies: gatewayProxy: disabled: true gloo: disableLeaderElection: true kubeGateway: enabled: true EOF 
Enter fullscreen mode Exit fullscreen mode

You should see something like this

NAME: gloo LAST DEPLOYED: Mon Mar 31 12:38:09 2025 NAMESPACE: gloo-system STATUS: deployed REVISION: 1 TEST SUITE: None 
Enter fullscreen mode Exit fullscreen mode

Once we have this the GatewayClass should be able to see Gloo Edge

kubectl get gatewayclass gloo-gateway NAME CONTROLLER ACCEPTED AGE gloo-gateway solo.io/gloo-gateway True 25m 
Enter fullscreen mode Exit fullscreen mode

Now that we have this let's create a Gateway

kubectl apply -n gloo-system -f- <<EOF kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: http spec: gatewayClassName: gloo-gateway listeners: - protocol: HTTP port: 8080 name: http allowedRoutes: namespaces: from: All EOF 
Enter fullscreen mode Exit fullscreen mode

Once we apply this we can check if the gateway is now created.

I also wanted to see how this looks by default, we have quite a lot of information here.

apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: creationTimestamp: "2025-03-31T07:21:45Z" generation: 1 name: http namespace: gloo-system resourceVersion: "75078" uid: 68dfe16f-12ef-4bfc-b20a-0515826721be spec: gatewayClassName: gloo-gateway listeners: - allowedRoutes: namespaces: from: All name: http port: 8080 protocol: HTTP status: conditions: - lastTransitionTime: "2025-03-31T07:21:45Z" message: "" observedGeneration: 1 reason: Accepted status: "True" type: Accepted - lastTransitionTime: "2025-03-31T07:21:45Z" message: "" observedGeneration: 1 reason: Programmed status: "True" type: Programmed listeners: - attachedRoutes: 0 conditions: - lastTransitionTime: "2025-03-31T07:21:45Z" message: "" observedGeneration: 1 reason: Accepted status: "True" type: Accepted - lastTransitionTime: "2025-03-31T07:21:45Z" message: "" observedGeneration: 1 reason: NoConflicts status: "False" type: Conflicted - lastTransitionTime: "2025-03-31T07:21:45Z" message: "" observedGeneration: 1 reason: ResolvedRefs status: "True" type: ResolvedRefs - lastTransitionTime: "2025-03-31T07:21:45Z" message: "" observedGeneration: 1 reason: Programmed status: "True" type: Programmed name: http supportedKinds: - group: gateway.networking.k8s.io kind: HTTPRoute 
Enter fullscreen mode Exit fullscreen mode

Now it's time to run some sample apps and test the gateway.

kubectl create ns httpbin kubectl -n httpbin apply -f https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/policy-demo/httpbin.yaml kubectl -n httpbin get pods 
Enter fullscreen mode Exit fullscreen mode

Now in order to expose the application, we have to create a HTTPRoute resource.

By definition

HTTPRoute is a Gateway API type for specifying routing behavior of HTTP requests from a Gateway listener to an API object, i.e. Service.

So if we have a service we can route to it using the HTTPRoute

The specification of an HTTPRoute consists of: ParentRefs- Define which Gateways this Route wants to be attached to. Hostnames (optional)- Define a list of hostnames to use for matching the Host header of HTTP requests. Rules- Define a list of rules to perform actions against matching HTTP requests. Each rule consists of matches, filters (optional), backendRefs (optional), timeouts (optional), and name (optional) fields. 
Enter fullscreen mode Exit fullscreen mode

(Taken from the official spec)

Back to our setup we can now setup the HTTPRoute

kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin namespace: httpbin labels: example: httpbin-route spec: parentRefs: - name: http namespace: gloo-system hostnames: - "www.example.com" rules: - backendRefs: - name: httpbin port: 8000 EOF 
Enter fullscreen mode Exit fullscreen mode

We can then check how this now looks in the cluster

kubectl get -n httpbin httproute/httpbin -o yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: creationTimestamp: "2025-03-31T07:44:46Z" generation: 1 labels: example: httpbin-route name: httpbin namespace: httpbin resourceVersion: "76943" uid: e0f81d5a-7377-4bda-bae1-ce5f36031251 spec: hostnames: - www.example.com parentRefs: - group: gateway.networking.k8s.io kind: Gateway name: http namespace: gloo-system rules: - backendRefs: - group: "" kind: Service name: httpbin port: 8000 weight: 1 matches: - path: type: PathPrefix value: / status: parents: - conditions: - lastTransitionTime: "2025-03-31T07:44:47Z" message: "" observedGeneration: 1 reason: Accepted status: "True" type: Accepted - lastTransitionTime: "2025-03-31T07:44:47Z" message: "" observedGeneration: 1 reason: ResolvedRefs status: "True" type: ResolvedRefs controllerName: solo.io/gloo-gateway parentRef: group: gateway.networking.k8s.io kind: Gateway name: http namespace: gloo-system 
Enter fullscreen mode Exit fullscreen mode

To test the gateway API we are now going to port-forward our setup.

kubectl port-forward deployment/gloo-proxy-http -n gloo-system 8080:8080 Forwarding from 127.0.0.1:8080 -> 8080 Forwarding from [::1]:8080 -> 8080 
Enter fullscreen mode Exit fullscreen mode

And this works as expected

curl -i localhost:8080/headers -H "host: www.example.com" Handling connection for 8080 HTTP/1.1 200 OK access-control-allow-credentials: true access-control-allow-origin: * content-type: application/json; encoding=utf-8 date: Mon, 31 Mar 2025 07:48:28 GMT content-length: 331 x-envoy-upstream-service-time: 0 server: envoy { "headers": { "Accept": [ "*/*" ], "Host": [ "www.example.com" ], "User-Agent": [ "curl/8.12.1" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "44449e3f-2442-4899-8238-0c2f70e1ee59" ] } } 
Enter fullscreen mode Exit fullscreen mode

Now that we have the basic setup, let's try something extra with this. I like that using Gloo Gateway means that I can route to traffic that is anywhere

Let's quickly try a static upstream.

To create a Static Upstream we can do the following

kubectl apply -f- <<EOF apiVersion: gloo.solo.io/v1 kind: Upstream metadata: name: json-upstream spec: static: hosts: - addr: jsonplaceholder.typicode.com port: 80 EOF 
Enter fullscreen mode Exit fullscreen mode

Then let's create a RouteOption, basically you can attach RouteOption to HTTPRoute as a Filter.

kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: RouteOption metadata: name: rewrite namespace: default spec: options: hostRewrite: 'jsonplaceholder.typicode.com' EOF 
Enter fullscreen mode Exit fullscreen mode

Let's also create a HTTPRoute

kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: static-upstream namespace: default spec: parentRefs: - name: http namespace: gloo-system hostnames: - static.example rules: - backendRefs: - name: json-upstream kind: Upstream group: gloo.solo.io filters: - type: ExtensionRef extensionRef: group: gateway.solo.io kind: RouteOption name: rewrite EOF 
Enter fullscreen mode Exit fullscreen mode

Now let's check our HTTPRoute

kubectl get httproute -A NAMESPACE NAME HOSTNAMES AGE default static-upstream ["static.example"] 11s httpbin httpbin ["www.example.com"] 8m11s 
Enter fullscreen mode Exit fullscreen mode
curl -ik localhost:8080/posts -H "host: static.example:8080" Handling connection for 8080 HTTP/1.1 200 OK date: Mon, 31 Mar 2025 07:54:29 GMT content-type: application/json; charset=utf-8 report-to: {"group":"heroku-nel","max_age":3600,"endpoints":[{"url":"https://nel.heroku.com/reports?ts=1743243502&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=geYoiMWFeqaCuv2HSvTjAatpMYLmT8EZc0f7Dd%2FnvDw%3D"}]} reporting-endpoints: heroku-nel=https://nel.heroku.com/reports?ts=1743243502&sid=e11707d5-02a7-43ef-b45e-2cf4d2036f7d&s=geYoiMWFeqaCuv2HSvTjAatpMYLmT8EZc0f7Dd%2FnvDw%3D nel: {"report_to":"heroku-nel","max_age":3600,"success_fraction":0.005,"failure_fraction":0.05,"response_headers":["Via"]} x-powered-by: Express x-ratelimit-limit: 1000 x-ratelimit-remaining: 999 x-ratelimit-reset: 1743243543 vary: Origin, Accept-Encoding access-control-allow-credentials: true cache-control: max-age=43200 pragma: no-cache expires: -1 x-content-type-options: nosniff etag: W/"6b80-Ybsq/K6GwwqrYkAsFxqDXGC7DoM" via: 1.1 vegur cf-cache-status: HIT age: 17 server: envoy cf-ray: 928e476ddad0424e-BOM alt-svc: h3=":443"; ma=86400 server-timing: cfL4;desc="?proto=TCP&rtt=1834&min_rtt=1834&rtt_var=917&sent=1&recv=3&lost=0&retrans=0&sent_bytes=0&recv_bytes=213&delivery_rate=0&cwnd=249&unsent_bytes=0&cid=0000000000000000&ts=0&x=0" x-envoy-upstream-service-time: 16 transfer-encoding: chunked [ { "userId": 1, "id": 1, "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" }, 
Enter fullscreen mode Exit fullscreen mode

And with that I would like to end this post, I will be testing this more, so I'll be posting about these.

Top comments (0)