Recently, a customer approached us with a problem. They use another vendor’s API gateway that checks the boxes for most of their requirements, with one notable exception: it fails on messages with elephantine payloads. They have requirements to issue requests that post up to gargantuan 100MB files. And adding another dimension to this porcine pickle, they would like to simultaneously have the gateway layer add arbitrary custom headers to be injected along with the upstream request. Can Gloo’s gateway technology help with such a problem?
In Part 1 of this post, we worked through this example using a dedicated Gloo Edge API gateway. Here in Part 2, we’ll work through the same example using Solo’s new Gloo API Gateway, built on top of Istio. In addition to offering equivalent gateway features, the Gloo API Gateway delivers the benefits of being integrated with the Istio control plane under Gloo management: multi-tenancy capabilities, superior cross-cluster operations, and more complete service observability.
But for this exercise, we’re strictly focused on the API Gateway as it can be adopted almost independently of any underlying service mesh. The larger benefits of Istio and Gloo Mesh are covered elsewhere.
So let’s get started. We invite you to follow along on your own Kubernetes cluster.
Prerequisites
To complete this guide, you’ll need a Kubernetes cluster and associated tools, plus an Istio deployment and an installation of Gloo Mesh Enterprise. We ran the tests in this blog on Gloo Mesh Enterprise v2.3.4 with Istio v1.17.2. We hosted all of this on a local instance of k3d v5.4.3.
You’ll need a license key to install Gloo Mesh Enterprise if you don’t already have one. You can obtain a key by initiating a free trial here.
For this exercise, we’ll also use some common CLI utilities like kubectl, curl, and git. Make sure these prerequisites are all available to you before jumping into the next section. I’m building this on MacOS but other platforms should be perfectly fine as well.
Clone Github Repo
The resources required for this exercise are available in the gloo-edge-use-cases
repo on Github. Clone that to your workstation and switch to the large-payload
example directory:
Install Gloo API Gateway
Since we’re just evaluating the API Gateway component of Gloo, you’ll only need a single k8s cluster active. However, if you already have multiple clusters in place, you can certainly use that configuration as well.
If you don’t have Istio or Gloo installed, there is a simplified installation script available in the Github repo you cloned in the previous section. Before you walk through that script, you’ll need three pieces of information.
- Place a Gloo license key in the environment variable
GLOO_GATEWAY_LICENSE_KEY
. If you don’t already have one of these, you can obtain it from your Solo account executive. - Supply a reference to the repo where the hardened Solo images for Istio live. This value belongs in the environment variable
ISTIO_REPO
. You can obtain the proper value from this location once you’re a Gloo Edge customer or have activated a free trial. - Supply a version string for Gloo Mesh Gateway in the environment variable
GLOO_MESH_VERSION
. For the tests we are running here, we usev2.3.4
.
From the gloo-gateway-use-cases
directory at the top level of the cloned repo, execute the setup script below. It will configure a local k3d cluster containing Istio with the Gloo API Gateway component activated. The script will fail if any of the three environment variables above is not present.
The output from the setup script should resemble what you see below. If you require a more complex installation, the complete Gloo Mesh installation guide is available here.
Install htttpbin Application
HTTPBIN is a great little REST service that can be used to test a variety of http operations and echo the response elements back to the consumer. We’ll use it throughout this exercise. First, we’ll install the httpbin service on our k3d cluster. Run:
You should see:
You can confirm that the httpbin pod is running by searching for pods with an app
label of httpbin
:
And you will see:
Generate Payload Files
If you’d like to follow along with this exercise, we’ll test our service using some preposterously large payloads that we generate for ourselves. (You wouldn’t want us to flood your network with these behemoths when you cloned our Github repo, would you?)
These commands all work on MacOS. Your mileage may vary on other platforms.
- 1MB:
base64 /dev/urandom | head -c 10000000 > large-payloads/1m-payload.txt
- 10MB:
base64 /dev/urandom | head -c 100000000 > large-payloads/10m-payload.txt
- 100MB:
base64 /dev/urandom | head -c 1000000000 > large-payloads/100m-payload.txt
Create a Workspace
A Workspace
is a really important new feature in Gloo Mesh 2.0. By providing a team-oriented artifact “container”, they make it much easier to express policies that clearly delineate boundaries between resources that are owned by various teams within your organization. The Workspaces
you specify in turn generate Istio artifacts that enforce multi-tenant-aware policies. You can learn more about them here.
In our case, we’re focused strictly on gateway functionality and not so much on shared tenancy. So we’ll create a namespace and a single Workspace
to reflect the domain of our ops-team
that is maintaining our gateway capability.
You can create the Workspace
above using this command:
You should see results like this:
Establish a VirtualGateway
Let’s establish a Gloo Mesh VirtualGateway
that we’ll attach to the default istio-ingressgateway
that was configured when we installed our local Istio instance earlier. We’ll configure this gateway to handle our inbound, north-south traffic by selecting any RouteTables
that are specified in the ops-team
workspace. We’ll create such a RouteTable
momentarily. Here is the VirtualGateway
YAML:
Now we’ll apply this configuration to establish the north-south gateway:
That should yield a result like this:
Configure a RouteTable
RouteTables
are a key Gloo API Gateway abstraction that specify routing policies to apply to requests. You can learn more about them in the request routing documentation here. For this exercise, we require just a simple RouteTable
that attaches to our north-south-gw
and routes all inbound requests to our httpbin service.
Let’s apply this configuration:
And observe that the RouteTable
was created as expected:
Add a TransformationPolicy
A Gloo API Gateway TransformationPolicy
provides an API for specifying a set of transformation rules to apply to an inbound request. These policies are quite expressive, and you can learn more about them here. In our case, we will simply inject a single custom header x-my-custom-header
with value my-custom-value
.
Note that we’ve specified a label selector on this policy to apply it to any route that has a label big-payload
set to true
. Look back at the RouteTable
in the previous section to see that that label is specified there.
Now let’s apply the policy:
Here’s the expected result:
Test, Test, Test
Managing with Marlin
Let’s not start with our full-grown, whale-sized payload. Instead, we’ll create a small clownfish-sized payload—we’ll call it Marlin—to get going. Note that Marlin swims upstream with its microscopic 100-byte payload with no problem. In addition, you can see the X-My-Custom-Header
with my-custom-value
that appears in the request headers that httpbin echoes back to the caller. So far, so good.
Cruising with Crush?
Marlin was no problem, so let’s move up the food chain by trying a sea turtle-sized payload that we’ll call Crush. Crush carries a 1MB payload, so he may create some cacophony.
This is not the response we wanted to see from Crush:
An HTTP 413 response indicates that we have overflowed Envoy’s default buffer size for a given request. Learn more about Envoy buffering and flow control here and here. It is possible to increase the Envoy buffer size, but this must be considered very carefully since multiple large requests with excessive buffer sizes could result in memory consumption issues for the proxy.
The good news is that for this use case we don’t require buffering of the request payload at all, since we are not contemplating transformations on the payload, which is what we see most commonly with cases like this. Instead, we’re simply delivering a large file to a service endpoint. The only transformation we require of the Envoy proxy is to add X-My-Custom-Header
to the input, which we have carried along since the original example.
Re-calibrating for Crush
So now we’ll apply a one-line change to our TransformationPolicy
that sets the optional passthrough flag. It is commonly used in use cases like this to instruct the proxy NOT to buffer the payload at all, but simply to pass it through unchanged to the upstream service.
Note that you will only want to use this technique in routes where you are NOT performing transformation based on the payload content, like using extraction to pull selected elements from the message body into request headers. Buffering is absolutely required for those transformation types, and enabling passthrough mode would likely cause mysterious and unexpected behavior.
Here is the one-line change to the TransformationPolicy
to enable massive message payloads:
Now apply the “passthrough” version of the TransformationPolicy
:
Expect this response:
Note that for this and all subsequent examples, we’ll suppress the native httpbin output because it wants to echo back the entire original request payload. And life is too short to watch all of that scroll by. Instead, we’ll rely on curl facilities to show just the response bits we care about: the total processing time, HTTP response code, and confirming the size of the request payload.
Now let’s retry Crush and watch him cruise all the way to Sydney with no constrictions:
Bashing with Bruce
Of course, the most fearsome payloads of all swim with Bruce, the great white shark. We’ll set our bulkiest payloads against the gateway with Bruce-sized proportions, 10MB first and then our ultimate goal of 100MB.
Finally, we achieve our goal of handling a 100MB payload:
Bruce ran the gauntlet with no problems, thanks to our passthrough
directive causing the proxy to bypass buffering of the payload.
Cleanup
If you’d like to clean up the work you’ve done, and if you’ve followed along closely with this example, then you can simply delete the k3d cluster you created in the beginning using the teardown script in our example repo:
Alternatively, if you brought your own cluster, then you can simply delete the Kubernetes namespaces we’ve created over the course of this exercise.
You should see a response like this that confirms the resources have been deleted.
Learn More about API Gateways
If you’ve followed along with us this far, then congratulations! You’ve not only navigated my gnarly Nemo puns and asinine alliterations, but you’ve also learned how to configure Gloo API Gateway to handle lavishly large message payloads.
For more information, check out the following resources.
- Review Part 1 of this blog post, where we solved the same large-request problem using Gloo Edge
- Explore the documentation for Gloo API Gateway.
- Request a live demo or trial for Gloo API Gateway.
- See video content on the solo.io YouTube channel.
- Questions? Join the Solo.io Slack community.