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 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 -

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 -<
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- <
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- <
Then let's create a RouteOption
, basically you can attach RouteOption
to HTTPRoute
as a Filter.
kubectl apply -f- <
Let's also create a HTTPRoute
kubectl apply -f- <
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.