Testing out Gateway API using Gloo Gateway
Leon Nunes

Leon Nunes @mediocredevops

About: He/Him. Dabbling in Service Meshes, API Gateways and Devops/Hardware/Homelabs

Location:
Remote
Joined:
Aug 22, 2020

Testing out Gateway API using Gloo Gateway

Publish Date: Mar 31
1 0

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.

Comments 0 total

    Add comment