This sub-module will cover the Istio service-mesh feature of rate limiting for network resiliency on Amazon EKS.
Use the following links to quickly jump to the desired section:
Apply Local Rate Limiting to the productcatalog
Service
kubectl apply -f local-ratelimit/local-ratelimit.yaml
Looking into the contents of the file local-ratelimit.yaml
- The HTTP_FILTER patch inserts the
envoy.filters.http.local_ratelimit
local envoy filter into the HTTP connection manager filter chain. - The local rate limit filter’s token bucket is configured to allow 10 requests/min.
- The filter is also configured to add an
x-local-rate-limit
response header to requests that are blocked.
To test the rate limiter in action, exec into the frontend
pod and send requests to the prodcatalog
service to trigger the rate limiter.
POD_NAME=$(kubectl get pod -l app=frontend -o jsonpath='{.items[0].metadata.name}' -n workshop)
kubectl exec $POD_NAME -n workshop -c frontend -- \
bash -c "for i in {1..20}; do curl -sI http://productcatalog:5000/products/; done"
Since the 20 requests are sent in less than a minute, after the first 10 requests are accepted by the service you’ll start seeing HTTP 429 response codes from the service.
Successful requests will return the following output:
HTTP/1.1 200 OK
content-type: application/json
content-length: 124
x-amzn-trace-id: Root=1-6502273f-8dd970ab66ed073ccd2519c7
access-control-allow-origin: *
server: envoy
date: Wed, 13 Sep 2023 21:18:55 GMT
x-envoy-upstream-service-time: 15
x-ratelimit-limit: 10
x-ratelimit-remaining: 9
x-ratelimit-reset: 45
While requests that are rate limited will return the following output:
HTTP/1.1 429 Too Many Requests
x-local-rate-limit: true
content-length: 18
content-type: text/plain
x-ratelimit-limit: 10
x-ratelimit-remaining: 0
x-ratelimit-reset: 45
date: Wed, 13 Sep 2023 21:18:55 GMT
server: envoy
x-envoy-upstream-service-time: 0
Similarly, if you run the same command without -I
flag, you will see the
responses as shown below:
For successful requests:
{
"products": {},
"details": {
"version": "2",
"vendors": [
"ABC.com, XYZ.com"
]
}
}
And for rate-limited requests:
local_rate_limited
To be able to use the Global Rate Limit in our Istio service-mesh we need a global rate limit service that implements Envoy’s rate limit service protocol.
- Configuration for the Global Rate Limit service
- Configuration is captured in
ratelimit-config
ConfigMap in the file global-ratelimit-config.yaml - As can be observed in the file, rate limit requests to the
/
path is set to 5 requests/minute and all other requests at 100 requests/minute.
- Configuration is captured in
- Global Rate Limit service with Redis
- File global-ratelimit-service.yaml
has Deployment and Service definitions for
- Central Rate Limit Service
- Redis
- File global-ratelimit-service.yaml
has Deployment and Service definitions for
Apply the Global Rate Limiting configuration and deploy the dependent services as shown below to the EKS cluster and Istio service-mesh.
kubectl apply -f global-ratelimit/global-ratelimit-config.yaml
kubectl apply -f global-ratelimit/global-ratelimit-service.yaml
Applying global rate limits is done in two steps:
-
Apply an EnvoyFilter to the ingressgateway to enable global rate limiting using Envoy’s global rate limit filter.
kubectl apply -f global-ratelimit/filter-ratelimit.yaml
Looking at the file filter-ratelimit.yaml
- The configuration inserts the
envoy.filters.http.ratelimit
global envoy filter into the HTTP_FILTER chain. - The
rate_limit_service
field specifies the external rate limit service,outbound|8081||ratelimit.workshop.svc.cluster.local
in this case.
- The configuration inserts the
-
Apply another EnvoyFilter to the ingressgateway that defines the route configuration on which to rate limit.
Looking at the file filter-ratelimit-svc.yaml
- The configuration adds rate limit actions for any route from a virtual host.
kubectl apply -f global-ratelimit/filter-ratelimit-svc.yaml
To test the global rate limit in action, run the following command in a terminal session:
ISTIO_INGRESS_URL=$(kubectl get svc istio-ingress -n istio-ingress -o jsonpath='{.status.loadBalancer.ingress[*].hostname}')
for i in {1..6}; do curl -Is $ISTIO_INGRESS_URL; done
In the output you should notice that the first 5 requests will generate output similar to the one below:
HTTP/1.1 200 OK
x-powered-by: Express
content-type: text/html; charset=utf-8
content-length: 1203
etag: W/"4b3-KO/ZeBhhZHNNKPbDwPiV/CU2EDU"
date: Wed, 17 Jan 2024 16:53:23 GMT
x-envoy-upstream-service-time: 34
server: istio-envoy
And the last request should generate output similar to:
HTTP/1.1 429 Too Many Requests
x-envoy-ratelimited: true
date: Wed, 17 Jan 2024 16:53:35 GMT
server: istio-envoy
transfer-encoding: chunked
We see this behavior because of the global rate limiting that is in effect that
is allowing only a max of 5 requests/minute when the context-path is /
Execute the following command to remove all rate-limiting configuration and services and then run the same steps as in the Initial state setup to reset the environment one last time.
# Delete all rate limiting configuration and services
kubectl delete -f ./local-ratelimit
kubectl delete -f ./global-ratelimit