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
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
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
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
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
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
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
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
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.
(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
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
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
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" ] } }
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
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
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
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
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" },
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)