[Tutorial] Rewriting Express Routes with Gloo Edge
Rewriting Express Routes with Gloo Edge
During this tutorial we are going to leverage Gloo Edge as an API Gateway and Kubernetes Ingress Controller to rewrite the routes of a simple Express app. You can clone the source code from here. The repository itself is packed with Scenarios that show off more features of Gloo Edge, but for this tutorial, we will only be focusing on rewriting routes, which is only but a very small part of the features that Gloo Edge is capable of, but it is a great place to start learning.
Prerequisites
- Have a Kubernetes environment with
kubectl
. I am using Docker Desktop for Mac with Kubernetes enabled, but minikube should also work just fine as an alternative local Kubernetes environment. - A linux environment to execute curl commands and install
glooctl
and Gloo Edge
Background
The Gloo Edge discovery services watch for new services added to the Kubernetes cluster. When we deploy our Express app called Tasks, Gloo Edge will automatically create an Upstream for the Task service.
Virtual Services define a set of route rules that live under a domain or set of domains. Route rules consist of matchers, which specify the kind of function calls to match, and the name of the destination (or destinations) where to route them.
Upstreams define destinations for routes. Upstreams tell Gloo Edge what to route to.
In this tutorial the upstream will be the Kubernetes Task Service, each Kubernetes Service will have a Virtual Service to control the flow of traffic.
Steps
- Clone the code locally
- Install
glooctl
- Install Gloo Edge API Gateway
- Deploy the Task application into Kubernetes
- Create rewrite rules in the Virtual Service to control traffic to the application using glooctl
- Export Virtual Services to yaml for quick deployment and to maintain good “infrastructure as code”
- Clean up
Clone the code locally
First we are going to install the code locally and change into the root directory of the repository.
git clone https://github.com/cmwylie19/task-service.git
cd task-service
Install glooctl
To install glooctl
, execute the proceeding command which downloads the binary and places it into your path.
curl -sL https://run.solo.io/gloo/install | sh
export PATH=$HOME/.gloo/bin:$PATH
Install Gloo Edge API Gateway
The easiest way to install Gloo Edge is using glooctl
.
glooctl install gateway
Deploy the Task application into Kubernetes
Now we will go ahead and deploy the Task Deployment and Service into Kubernetes.
kubectl apply -f k8s/task-service.yaml
Rewrite routes in a Virtual Service
Gloo Edge watches for new services to be added to the Kubernetes Cluster. When the application is created, Gloo Edge automatically creates an Upstream for the Kubernetes Service. Remember, upstream is the destination for the routes in the Virtual Service which will route to your Kubernetes Service. Gloo Edge also creates Virtual Services for the Kubernetes Services that control how traffic is routed to the Kubernetes Service.
By default, Gloo Edge will not route traffic until we add routing rules on a Virtual Service.
Now, before we get ahead of ourselves and start writing rules to reroute the service it is important to understand which routes we are rewriting.
Currently in the Task app we have the following endpoints:
POST /create - create task
GET / - retrieve all posts
GET /:id - retrieve specific post
PUT /:id - update specific post
DELETE /:id - delete specific post
GET /check/healthz - check if the service is up
NOTE– If you haven’t already I would encourage you to read the README.md
to learn how to interact with the application locally, and the DeployInK8s.md
if you have questions about how this app got containerized or how to deploy it in Kubernetes and expose it to the outside world.
Now that we deployed Gloo Edge, it will act as a Kubernetes Ingress Controller, and we have a Virtual Service in front of our application. We will need to create new routes to communicate with the application.
To see the existing Virtual Service that is in front of our application, do the following command:
glooctl get vs default -o yaml
The first thing we are going to do is update the Virtual Service to create new routes for the existing POST /create
and GET /
endpoints. The goal is to rewrite the /create
route to be /api/v1/create
and and the /
route to /api/v1/tasks
. These routes already exist in the exported Virtual Service k8s/vs-rewrite.yaml
.
This yaml file contains the two new routes that were alluded to earlier, /api/v1/create
and /api/v1/tasks
:
routes:
- matchers:
- exact: /api/v1/create
options:
prefixRewrite: /create
routeAction:
single:
upstream:
name: default-task-service-8080
namespace: gloo-system
- matchers:
- exact: /api/v1/tasks
options:
prefixRewrite: /
routeAction:
single:
upstream:
name: default-task-service-8080
namespace: gloo-system
Go ahead and apply the Virtual Service with the new routes:
kubectl apply -f k8s/vs-rewrite.yaml
Now that we have applied the new routing rules in the Virtual Service we will test the new routes to make sure they are working as expected.
Before we do, we will use glooctl
to checkout the VirtualService that houses these routes.
glooctl get vs
output:
+-----------------+--------------+---------+------+----------+-----------------+---------------------------------------+
| VIRTUAL SERVICE | DISPLAY NAME | DOMAINS | SSL | STATUS | LISTENERPLUGINS | ROUTES |
+-----------------+--------------+---------+------+----------+-----------------+---------------------------------------+
| default | | * | none | Accepted | | /api/v1/create -> |
| | | | | | | gloo-system.default-task-service-8080 |
| | | | | | | (upstream) |
| | | | | | | /api/v1/tasks -> |
| | | | | | | gloo-system.default-task-service-8080 |
| | | | | | | (upstream) |
+-----------------+--------------+---------+------+----------+-----------------+---------------------------------------+
We can see by the output that we have a VirtualService default
with routes /api/v1/create
and /api/v1/tasks
routing to an Upstream default-task-service-8080
in the namespace gloo-system
.
SIDE NOTE If you ever find yourself stuck debugging, a good place to start is looking at the logs from the gloo
pod in gloo-system.
kubectl get pods -n gloo-system
kubectl logs -f <pod-name>
Now that we have applied the Virtual Service from the yaml file, we are going to test it. First we are going to test our new route /api/v1/create
curl -X POST -H "Content-Type: application/json" -d '{"name":"test"}' $(glooctl proxy url)/api/v1/create
expected output:
Created{
"id": "0ea005c7686",
"name": "test",
"complete": false
}%
You see a similar output to the one that you ran when you POST /create
locally.
Now we will test the GET /
with the new route specified in the Virtual Service.
curl $(glooctl proxy url)/api/v1/tasks
expected output:
[{"id":"0ea005c7686","name":"test","complete":false}]%
Again, you should have seen the same results as you did when you executed before running locally.
Next, we are going to write a new routing rule for the GET /check/healthz
endpoint. We are going to write this rule now using the glooctl
cli tool which will automatically add the routing rule to our Virtual Service.
glooctl add route \
--path-exact /api/v1/healthz \
--dest-name default-task-service-8080 \
--prefix-rewrite /check/healthz
It goes without saying but make sure the --dest-name
is the appropriate upstream for our app. I have used the wrong upstream once or twice and had to dig into the logs of the gloo
pod to figure out why my routes were not working.
This command will create a new route, /api/v1/healthz
on the Upstream default-task-service-8080
from the old route /check/healthz
.
Lets test this new route: If all goes correctly, we should recievea response of pong
back from the task-service.
curl $(glooctl proxy url)/api/v1/healthz
expected output:
pong!%
Now that we understand how to create routes in the Virtual Service yaml and from the command line with glooctl
, lets export the the Virtual Service to yaml to maintain good infrastructure as code.
You can find the name of the Virtual Service with the command: glooctl get vs
Now, lets export the default
Virtual Service to yaml, sanitize it(delete fields, status
, metadata.generation
, getadata,creationTimestamp
, metadata.uid
, matadata.selfLink
, metadata.resourceVersion
, and put it back into GIT under k8s/vs-rewrite-healthz.yaml
so that we can quickly apply the yaml file to get our Virtual Service up and running without having to manually create routes again or to allow a GitOps tool like ArgoCD
to manage our configuration as code by comparing the Yamls in the k8s
directory with the resources in Kubernetes. If you are not familiar with yaml sanitization, check out the k8s/vs-rewrite-final.yaml
to see how a correctly sanitized yaml file should look.
kubectl get vs -n gloo-system default -o yaml > k8s/vs-rewrite-default.yaml
The last thing I want to touch on in this tutorial is how to add a route that has a parameter to the Virtual Service, like our routes that have the format of /:id
. Those routes will match the prefix of /api/v1/tasks/
. Make SURE to add the trailing /
or they will not match!
The finished Virtual Service with each route rewritten can be found in k8s/vs-rewrite-final.yaml
.
Apply the finished Virtual Service and try out the routes:
kubectl apply -f k8s/vs-rewrite-final.yaml
Your new, more elegant and descriptive endpoints resemble the following:
POST /api/v1/create - create task
GET /api/v1/tasks - retrieve all posts
GET /api/v1/tasks/:id - retrieve specific post
PUT /api/v1/tasks/:id - update specific post
DELETE /api/v1/tasks/:id - delete specific post
GET /api/v1/healthz - check if the service is up
After you sanitize the yaml file for the default VirtualService you have completed this tutorial. In future tutorials I plan on using the same Express Task application to demonstrate even more advanced capabilities of Gloo Edge.
Clean Up
Delete the virtual service
kubectl delete vs default -n gloo-system
Delete the upstream
kubectl delete upstream -n gloo-system default-task-service-8080
Delete the task-service Deployment and Service
kubectl delete svc,deployment task-service
Learn More
You can learn more about Gloo Edge by checking out the docs!
Feel free to reach out to me to talk shop or for questions!