As we’ve written before, rate limiting is a useful tool with distributed systems. In Kubernetes applications, rate limiting is often used to control the rate of traffic sent or received to a service. There are three popular use cases for implementing rate limiting cloud native applications:

Preventing a denial of service (intentional or otherwise) through resource exhaustion

Limiting the impact of cascading failure

Restricting or metering resource usage

The Ambassador Edge Stack’s rate limiting service is highly flexible and can be used to implement any of these strategies. In this article, I’ll cover how rate limiting is configured in the Ambassador Edge Stack and show you how to set it up for your own Kubernetes services.

The Basic Configuration Objects

Rate limits in the Ambassador Edge Stack are composed of two parts.

Labels

A label is basic metadata that is used by the rate limiting service and is applied to a request. The Ambassador Edge Stack supports three types of labels:

generic_key a simple string

a simple string remote_address the value of the client IP address (assuming you have configured the load balancer correctly)

the value of the client IP address (assuming you have configured the load balancer correctly) a custom type that can forward the value of a header to Ambassador for rate limiting

RateLimits

RateLimits set limits based on the labels in the request.

Global vs. Service-Level Rate Limits

The Ambassador Edge Stack supports both global and service-level rate limits by two different labeling mechanisms.

Labels applied at the ambassador Module are global and applied to every single request that goes through Ambassador

Module are global and applied to every single request that goes through Ambassador Labels applied at the Mapping are service-level and applied only to the requests that use that Mapping

Basic Rate Limiting

Now that we’ve defined the different configuration objects, let’s walk through how we can use them to set up basic rate limiting in a Kubernetes application.

Labels applied at the Module are applied to every request. So if I configure a Module like this:

Every request through Ambassador will then carry label metadata like {"generic_key": "default_generic_key_label"} and I will then be able to create a basic default rate limit on every request through Ambassador with the RateLimit here:

Likewise, if instead I want to just limit requests to a single service, I could configure a Mapping like this:

Requests to the foo-app , will then carry label metadata like {"generic_key": "foo-app_generic_key_label"} and I will then be able to create a rate limit on requests to the foo-app with the RateLimit below:

Advanced Rate Limiting

Now that we have covered a basic use case for rate limiting, we can get into more advanced topics.

As you may have noticed, there is a concept of grouping in the way labels are created. This allows me to have a single request count against multiple different RateLimit s. For example, if I wanted to enable a limit on the number of total requests a user could send to a couple of endpoints but also want to enforce stricter limits on a single application, Icould create labels in the different Mapping s like this:

Now, requests to the foo-app and the bar-app , carry label metadata like {{"generic_key": "foo-app"},{"remote_address", 10.10.11.12}} and {{"generic_key": "bar-app"},{"remote_address", 10.10.11.12}} respectively. Now I can create rate limits on requests to the foo-app , bar-app , and the combination with the RateLimit s below:

Finally, it’s important to understand how the “global” labels configured in the Module affect this.

The labels configured in a Module are prepended to every single label group. So, if I had the same multiple-mapping rate limit config above, and added the following Module :

The labels metadata would change from:

{{"generic_key": "foo-app"},{"remote_address", 10.10.11.12}} and

{{"generic_key": "bar-app"},{"remote_address", 10.10.11.12}}

to:

{{"generic_key": "default", "generic_key": "foo-app"},{"generic_key": "default", "remote_address", 10.10.11.12}} and

{{"generic_key": "default", "generic_key": "bar-app"},{"generic_key": "default", "remote_address", 10.10.11.12}}

and thus the RateLimit s would need to change to appropriately handle the new labels:

Conclusion

I hope that this article helps you understand how to set up rate limiting for your Kubernetes services with the Ambassador Edge Stack. For more examples, you can check out the documentation.

The Ambassador Edge Stack is a Kubernetes-native API gateway designed to support the architecture and full-cycle development workflows that dramatically accelerates application development. If you haven’t yet installed the Ambassador Edge Stack, you can follow the Quickstart guide to get going in just a few minutes. If you have any questions or you need help getting set up, join our Slack channel.