From d8b4438da234ddd3c6efbbb4b36b49f1a329e442 Mon Sep 17 00:00:00 2001 From: Nupur Garg <37600866+gargnupur@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:46:03 -0800 Subject: [PATCH] Add Ratelimit Task using Envoy (#8537) * Add Ratelimit Task * Fix lint * Fix lint * Fixed based on feedback * Apply suggestions from code review Co-authored-by: Frank Budinsky * Adding Doug's suggestion.. din't get applied through UI * fix lint * Apply suggestions from code review Co-authored-by: Douglas Reid * fixed based on feedback * fixed vhost * fix some lint errors * fix some lint errors * Apply suggestions from code review Co-authored-by: Frank Budinsky * fix indent * add extra space for lint error * fix lint issues Co-authored-by: Frank Budinsky Co-authored-by: Douglas Reid Co-authored-by: Douglas Reid --- .spelling | 2 + .../policy-enforcement/rate-limit/index.md | 333 ++++++++++++++++++ 2 files changed, 335 insertions(+) create mode 100644 content/en/docs/tasks/policy-enforcement/rate-limit/index.md diff --git a/.spelling b/.spelling index f997904f6e..8fc7bdc09a 100644 --- a/.spelling +++ b/.spelling @@ -721,6 +721,8 @@ vCPUs versioned versioning veth-pair +vhost +vhosts virtualization Virtualization virtualservices-destrules diff --git a/content/en/docs/tasks/policy-enforcement/rate-limit/index.md b/content/en/docs/tasks/policy-enforcement/rate-limit/index.md new file mode 100644 index 0000000000..473aae8f5a --- /dev/null +++ b/content/en/docs/tasks/policy-enforcement/rate-limit/index.md @@ -0,0 +1,333 @@ +--- +title: Enabling Rate Limits using Envoy +description: This task shows you how to use Istio to dynamically limit the traffic to a service. +weight: 10 +keywords: [policies,quotas] +owner: istio/wg-policies-and-telemetry-maintainers +test: no +--- + +This task shows you how to use Envoy's native rate limiting in Istio to dynamically limit the traffic to a +service. In this task, we will apply a global rate-limit for the `productpage` service through ingress gateway that allows +1 requests per minute across all instances of the service. Additionally, we will apply a local rate-limit for each +individual `productpage` instance that will allow 10 requests per minute. In this way, we will ensure that our `productpage` +service handles a maximum of 1 requests per minute through instance gateway, but each `productpage` instance can handle +up to 10 requests per minute allowing for any in-mesh traffic. + +## Before you begin + +1. Setup Istio in a Kubernetes cluster by following the instructions in the + [Installation Guide](/docs/setup/getting-started/). + +1. Deploy the [Bookinfo](/docs/examples/bookinfo/) sample application. + +## Rate limits + +Envoy supports two kinds of rate limiting: global and local. Global rate +limiting uses a global gRPC rate limiting service to provide rate limiting for the entire mesh. +Local rate limiting is used to limit the rate of requests per service instance. +Local rate limiting can be used in conjunction with global rate limiting to reduce load on +the global rate limiting service. + +In this task you will configure Envoy to rate limit traffic to a specific path of a service +using both global and local rate limits. + +### Global rate limit + +Envoy can be used to [set up global rate limits](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/other_features/global_rate_limiting) for your mesh. + +1. Global rate limiting in Envoy uses a gRPC API for requesting quota from a rate limiting service. + A [reference implementation](https://github.com/envoyproxy/ratelimit) of the API, written in Go with a Redis + backend, is used below. + + The following [configmap](https://github.com/envoyproxy/ratelimit#configuration) configures the + reference implementation to rate limit requests to the path `/productpage` at 1 req/min and all other + requests at 100 req/min. + + {{< text yaml >}} + apiVersion: v1 + kind: ConfigMap + metadata: + name: ratelimit-config + data: + config.yaml: | + domain: productpage-ratelimit + descriptors: + - key: PATH + value: "/productpage" + rate_limit: + unit: minute + requests_per_unit: 1 + - key: PATH + rate_limit: + unit: minute + requests_per_unit: 100 + {{< /text >}} + +1. Apply an `EnvoyFilter` to the `ingressgateway` to enable global rate limiting using Envoy's global rate limit filter. + + The first patch inserts the + `envoy.filters.http.ratelimit` [global envoy filter](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ratelimit/v3/rate_limit.proto#envoy-v3-api-msg-extensions-filters-http-ratelimit-v3-ratelimit) filter into the `HTTP_FILTER` chain. + The `rate_limit_service` field specifies the external rate limit service, `rate_limit_cluster` in this case. + + The second patch defines the `rate_limit_cluster`, which provides the endpoint location of the external rate limit service. + + {{< text bash >}} + $ kubectl apply -f - <}} + +1. Apply another `EnvoyFilter` to the `ingressgateway` that defines the route configuration on which to rate limit. + This adds [rate limit actions](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-msg-config-route-v3-ratelimit) + for any route from a virtual host named `*.80`. + + {{< text bash >}} + $ kubectl apply -f - <}} + +### Local rate limit + +Envoy supports [local rate limiting](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/other_features/local_rate_limiting#arch-overview-local-rate-limit) of L4 connections and HTTP requests. +This allows you to apply rate limits at the instance level, in the proxy itself, without calling any other service. + +The following `EnvoyFilter` enables local rate limiting for any traffic through the `productpage` service. +The `HTTP_FILTER` patch inserts the `envoy.filters.http.local_ratelimit` [local envoy filter](https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/local_rate_limit_filter#config-http-filters-local-rate-limit) +into the HTTP connection manager filter chain. The local rate limit filter's [token bucket](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/local_ratelimit/v3/local_rate_limit.proto#envoy-v3-api-field-extensions-filters-http-local-ratelimit-v3-localratelimit-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. + +{{< text bash >}} +$ kubectl apply -f - <}} + +The above configuration applies local rate limiting to all vhosts/routes. Alternatively, you can restrict it to a specific route. + +The following `EnvoyFilter` enables local rate limiting for any traffic to port 80 of the `productpage` service. +Unlike the previous configuration, there is no `token_bucket` included in the `HTTP_FILTER` patch. +The `token_bucket` is instead defined in the second (`HTTP_ROUTE`) patch which includes a `typed_per_filter_config` for the `envoy.filters.http.local_ratelimit` +local envoy filter, for routes to virtual host `inbound|http|9080`. + +{{< text bash >}} +$ kubectl apply -f - <}} + +## Verify the results + +### Verify global rate limit + +Send traffic to the Bookinfo sample. Visit `http://$GATEWAY_URL/productpage` in your web +browser or issue the following command: + +{{< text bash >}} +$ curl "http://$GATEWAY_URL/productpage" +{{< /text >}} + +{{< tip >}} +`$GATEWAY_URL` is the value set in the [Bookinfo](/docs/examples/bookinfo/) example. +{{< /tip >}} + +You will see the first request go through but every following request within a minute will get a 429 response. + +### Verify local rate limit + +Although the global rate limit at the ingress gateway limits requests to the `productpage` service at 1 req/min, +the local rate limit for `productpage` instances allows 10 req/min. +To confirm this, send internal `productpage` requests, from the `ratings` pod, using the following `curl` command: + +{{< text bash >}} +$ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl productpage:9080/productpage | grep -o ".*" +Simple Bookstore App +{{< /text >}} + +You should see no more than 10 req/min go through per `productpage` instance.