Traefik comes with a default rate limiter middleware, but the rate limiter doesn't share a state if you are using several instance of Traefik (think kubernetes HA deployment for example).
This plugin is here to solve this issue: using a Redis as a common state, this plugin implement the token bucket algorithm.
You need to setup the static and dynamic configuration
The following declaration (given here in YAML) defines the plugin:
# Static configurationexperimental:plugins:clusterRatelimit:moduleName: "github.com/nzin/traefik-cluster-ratelimit"version: "v1.1.1"
Here is an example of a file provider dynamic configuration (given here in YAML), where the interesting part is the http.middlewares section:
# Dynamic configurationhttp:routers:my-router:rule: host(`demo.localhost`)service: service-fooentryPoints:- webmiddlewares:- my-middlewareservices:service-foo:loadBalancer:servers:- url: http://127.0.0.1:5000middlewares:my-middleware:plugin:clusterRatelimit:average: 50burst: 100
With a kubernetesingress provider:
apiVersion: traefik.io/v1alpha1kind: Middlewaremetadata:name: clusterratelimitnamespace: ingress-traefikspec:clusterRatelimit:average: 100burst: 200---apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: example-ingressnamespace: ingress-traefikannotations:traefik.ingress.kubernetes.io/router.middlewares: ingress-traefik-clusterratelimit@kubernetescrdspec:rules:- host: example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: example-serviceport:number: 80
The average
and the burst
are the number of allowed connection per second, there are other variables:
Variable | Description | default |
---|---|---|
period | the period (in seconds) of the rate limiter window | 1 |
average | allowed requests per "period" ( 0 = unlimited) | |
burst | allowed burst requests per "period" | |
redisAddress | address of the redis server | redis:6379 |
redisDb | redis db to use | 0 |
redisPassword | redis authentication (if any) | |
sourceCriterion.* | defines what criterion is used to group requests. See next | ipStrategy |
sourceCriterion.ipStrategy | client IP based source | |
sourceCriterion.ipStrategy.depth | tells Traefik to use the X-Forwarded-For header and select the IP located at the depth position | |
sourceCriterion.ipStrategy.excludedIPs | list of X-Forwarded-For IPs that are to be excluded | |
sourceCriterion.requestHost | based source on request host | |
sourceCriterion.requestHeaderName | Name of the header used to group incoming requests | |
breakerThreshold | number of failed connection before pausing Redis | 3 |
breakerReattempt | nb seconds before attempting to reconnect to Redis | 15 |
redisConnectionTimeout | redis connection timeout (in seconds) | 2 |
Notes:
$REDIS_PASSWORD
will use the REDIS_PASSWORD
environment variableA full example would be
# Dynamic configurationhttp:...middlewares:my-middleware:plugin:clusterRatelimit:average: 5burst: 10period: 10sourceCriterion:ipStrategy:depth: 2excludedIPs:- 127.0.0.1/32- 192.168.1.7redisAddress: redis:6379redisPassword: $REDIS_AUTH_PASSWORDredisConnectionTimeout: 2
If the Redis server is not available, we will stop talking to it, and let pass through.
As mentionned above there are 2 variables you can use to change the default behaviour: breakerThreshold
and breakerReattempt
. Usually you dont need to tweak that.
You can test traefik with the rate limiter with some tools. For example with vegeta (you probably need to install it):
docker-compose up -decho "GET http://localhost:8000/" | vegeta attack -duration=5s -rate=200 | tee results.bin | vegeta report