diff --git a/docs/contributor/adr/0007-rate-limit.md b/docs/contributor/adr/0007-rate-limit.md new file mode 100644 index 0000000000..c7841aba33 --- /dev/null +++ b/docs/contributor/adr/0007-rate-limit.md @@ -0,0 +1,28 @@ +# Rate Limit + +## Status + +Draft + +## Context + +It has been decided to indroduce rate limit functionality into Kyma platform to allow users to set rate limit functionality on the service mesh layer, therefore allowing to consume intended service mesh functionality which is abstracting away networking concerns outside applications inside the mesh. +Since Istio is an underlying service mesh responsible for the workloads networking across Kyma clusters, therefore it is the Istio which allows to configure such functionality. +Taking that into account Goat Team is responsible to introduce this feature. +At this moment it is not possible to introduce global rate limit provided by Istio service mesh because of technical or legal limitations related to the deployment of key-value stores in the cluster. + +## Decision + +Taking the context part into account, it was decided to implement local rate limit as the only rate limiting posibility for now. +It is not said that the rate limit functionality will not be extended also to global rate limit in the future, therefore implemented api consider future extension with global rate limit. +It has been decided that this functionality will be exposed with another CRD in the Istio module. +Since Istio CRD is responsible for the mesh configuration mostly residing in the Istio's `meshConfig`, good decision seemed to be a creation of the new CRD. +There is no 100% certainity about introduction of global rate limit in the future, so Istio Module teamdecided to use naming RateLimit not containing local in it to not to impose that there will be also global. +Local rate limit uses buckets concept to control rate limit. To enable users to use more simplified form, except exposing Envoy's native api structure allowing for the bucket configuration, simplified form is provided allowing to use simple time units and requests allowed per given time period. +Currently the possibilites for rate limit functionality are limited to restrict number of requests, without considering any other criterias like header presence or header value. +CRD is structured in a way that allows further extensions, allowing to configure different rate limit criterias. + +## Consequences + +Istio Module team has to introduce another CRD with a controller loop into the module. +User has possibility to configure local rate limit in much friendler way through Istio Module abstraction, avoiding complexity of Envoy Filter, and is not exposed to the Envoy internal details, that are prone for changes. diff --git a/docs/contributor/draft/rate-limit-api.md b/docs/contributor/draft/rate-limit-api.md new file mode 100644 index 0000000000..2491ad4183 --- /dev/null +++ b/docs/contributor/draft/rate-limit-api.md @@ -0,0 +1,121 @@ +# Rate Limit Proposal + +## Spec + +| field | type | description | required | +|--------------------------------------------------|-------------|-----------------------------------------------------------------|-------------------------------| +| wokloadSelector | object | in case of empty, it's applied for the whole namespace | no | +| workloadSelector.labels | object | allows to select given workload by a selector | no | +| localRateLimit | object | allows to describe local rate limit properties | yes | +| localRateLimit.by | object | container for criteria you can limit by (for the future) | yes | +| localRateLimit.by.requests | object | allows to set rate limit based on plain number of requests | yes | +| localRateLimit.by.requests.time | object | allows to describe local rate limiting using time periods | yes (if buckets not defined) | +| localRateLimit.by.requests.buckets | object | allows to describe local rate limiting using buckets | yes (if time not defined) | +| localRateLimit.by.requests.time.unit | string | describes unit of time for rate limit | yes | +| localRateLimit.by.requests.time.requestsLimit | int |describes requests limit for a declared time unit | yes | +| localRateLimit.by.requests.buckets.maxTokens | int |describes max amount of tokens that can stack up | yes | +| localRateLimit.by.requests.buckets.tokensPerFill | int | describes how many tokens to fill every defined period of time | yes | +| localRateLimit.by.requests.buckets.fillInterval | time | describes how often fill tokens | yes | + +## Usage example + +```yaml +apiVersion: operator.kyma-project.io/v1alpha1 +kind: RateLimit +metadata: + name: httpbin-local-rate-limit + namespace: default +spec: + workloadSelector: + labels: + app: httpbin + localRateLimit: + by: + requests: + time: # exclusive with buckets, got to choose one + unit: "second" + requestsLimit: 30 + buckets: + max_tokens: 1000 + tokens_per_fill: 1000 + fill_interval: 1s + +--- + +# eventually we could extend it later into such direction + +apiVersion: operator.kyma-project.io/v1alpha1 +kind: RateLimit +metadata: + name: default + namespace: kyma-system +spec: + workloadSelector: + labels: + app: httpbin + localRateLimit: # separating it like this allows to extend fields with new use cases. Also every field can be extended with it's specifics + requests: + time: + unit: "second" + requestsLimit: 30 + buckets: + max_tokens: 1000 + tokens_per_fill: 1000 + fill_interval: 1s + headerPresence: + time: + unit: "second" + requestsLimit: 30 + buckets: + max_tokens: 1000 + tokens_per_fill: 1000 + fill_interval: 1s + headerName: "some-header" + vhost: "some.v.host" + route: "/some/path" + # plus any aditional fields specific for given use case + headerValue: + time: + unit: "second" + requestsLimit: 30 + buckets: + max_tokens: 1000 + tokens_per_fill: 1000 + fill_interval: 1s + headerName: "some-header" + headerValue: "some-value" + vhost: "some.v.host" + route: "/some/path" + clientCert: + time: + unit: "second" + requestsLimit: 30 + buckets: + max_tokens: 1000 + tokens_per_fill: 1000 + fill_interval: 1s + etc: "etc" + globalRateLimit: + requests: + time: + unit: "second" + requestsLimit: 30 + buckets: + max_tokens: 1000 + tokens_per_fill: 1000 + fill_interval: 1s + headerPresence: + time: + unit: "second" + requestsLimit: 30 + buckets: + max_tokens: 1000 + tokens_per_fill: 1000 + fill_interval: 1s + headerName: "some-header" + vhost: "some.v.host" + route: "/some/path" + # plus any aditional fields specific for given use case + etc: + etc: +``` diff --git a/docs/contributor/draft/rate-limit-api.yaml b/docs/contributor/draft/rate-limit-api.yaml deleted file mode 100644 index 0509b407d1..0000000000 --- a/docs/contributor/draft/rate-limit-api.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# Since combining local and global rate limit in one CR would make API more complex -# I would avoid doing so, and in case of extending Istio Module capabilities -# to global rate limit, I'd introduce new CRD. This way we would make use of our API easier. -# User would create LocalRateLimit and GlobalRateLimit custom objects separately -# One LocalRateLimit per workload for which rate limit is applied. -# This way it's easier for user to keep service related resources in one place. -# Also avoiding long yamls in case of big clusters with big amounts of workloads - -# This is how we could introduce it for now covering simple rate limiting without any specific selectors -apiVersion: operator.kyma-project.io/v1alpha1 -kind: LocalRateLimit -metadata: - name: httpbin-local-rate-limit - namespace: default -spec: - workloadSelector: - labels: - app: httpbin - rateLimitBy: - requests: - timeUnit: "second" - requestsLimit: 30 - ---- -# eventually we could extend it later into such direction -apiVersion: operator.kyma-project.io/v1alpha1 -kind: LocalRateLimit -metadata: - name: default - namespace: kyma-system -spec: - workloadSelector: - labels: - app: httpbin - rateLimitBy: # separating it like this allows to extend fields with new use cases. Also every field can be extended with it's specifics - requests: - timeUnit: "second" - requestsLimit: 30 - headerPresence: - headerName: "some-header" - timeUnit: "second" - requestsLimit: 30 - vhost: "some.v.host" - route: "/some/path" - # plus any aditional fields specific for given use case - headerValue: - headerName: "some-header" - headerValue: "some-value" - timeUnit: "minute" - requestsLimit: 10 - vhost: "some.v.host" - route: "/some/path" - clientCert: - etc: "etc"