Adventures in Path Based Routing
Path based routing can be an extremely useful feature. It enables you to serve a single page app and an API on the same domain. This can often be helpful when starting a project, but don’t want to handle things like cross-origin resource sharing. In a recent project, I wanted to split traffic between a static site hosted on GitHub (or S3) and an API running in the cluster. In this post, I’ll demonstrate some less common approaches to path based routing using Kubernetes resources.
Kubernetes supports routing HTTP requests via an
This directs processes known as ingress controllers to route communication for a host / path pair to a given backend service.
Services represent to a collection of backend pods, which are mapped through Endpoints (soon to be EndpointSlices).
They come in several variations:
In this post, we will focus two,
To continue the spirit of keeping posts lighter on code, all configuration used today is available on GitHub.
It provides a minimal footprint to show how to connect the parts together.
Some files require bringing your own values (such as a
Before getting into the ingress, let’s deploy an api-service stub.
This can act as a placeholder for your real API if you don’t yet have one. This service will handle all API requests.
Manually configured ClusterIP
First, I will demonstrate how to manually configure a
ClusterIP service to point to GitHub pages.
Using an ingress definition, we will split traffic between two backends.
/api/ will be sent to an
All other requests will be routed to GitHub pages.
This is shown in the diagram below.
First, we’ll create the
This file sets up the service, and it’s associated endpoint.
The IP addresses for the endpoint can be obtained by looking up the nameservers for
Once created, you will have a
This allows us to point our ingress definition directly at GitHub pages.
Applying our ingress configuration, will allow traffic to flow seamlessly between the two systems.
Using a CNAME
Next, I will demonstrate how an
ExternalName can be used to point to an S3 bucket.
We will be using a similar ingress setup (as seen below).
This time, we will use an
ExternalName service instead of a
ExternalNames are more or less a DNS CNAME.
They allow us to reference another host address that’s serving our content.
Once created, you will have an
This allows us to point our ingress definition directly at the S3 backend.
Similarly, we can deploy the ingress and have communication flow seamlessly between the systems.
Tips and Tricks
For small numbers of paths, path based routing is fine. If you find that you’re spawning more and more routes, managing them can become difficult.
Backends should serve on the paths they’re listening on
Having application logic that binds to a specific path can often be clunky for developers. Subdomains tradeoff the complexity of path management (from an development AND operational standpoint) for the complexity of CORS.
docker-registry is a great example of a service that can be deployed in such a manner.
The registry only serves requests on
/v2/, making it an easy target.
docker-auth can be added to lock down access.
It only needs access to your authentication path (
Finally, you can throw an open source UI on the
/ to give visitors an easy to use UI.
For a starting point, take a look at my previous blog post on my docker registry setup.