• GitHub
  • Slack
  • Linkerd Forum

Configuring Rate Limiting

In this guide, we’ll walk you through deploying an HTTPLocalRateLimitPolicy resource to rate-limit the traffic to a given service.

For more information about Linkerd’s rate limiting check the Rate Limiting feature doc and the HTTPLocalRateLimitPolicy reference doc.

To see how clients can be configured to load balance around Services which are rate-limited, see Rate Limit Aware Load Balancing.

Prerequisites

To use this guide you’ll only need a Kubernetes cluster running a Linkerd instance. You can follow the installing Linkerd Guide.

Setup

First inject and install the Emojivoto application, then scale-down the vote-bot workload to avoid it interfering with our testing:

linkerd inject https://run.linkerd.io/emojivoto.yml | kubectl apply -f -
kubectl -n emojivoto scale --replicas 0 deploy/vote-bot

Finally, deploy a workload with an Ubuntu image, open a shell into it and install curl:

kubectl create deployment client --image ubuntu -- bash -c "sleep infinity"
kubectl exec -it client-xxx -- bash
root@client-xxx:/# apt-get update && apt-get install -y curl

Leave that shell open so we can use it below when sending requests.

Creating an HTTPLocalRateLimitPolicy resource

We need first to create a Server resource pointing to the web-svc service. Note that this Server has accessPolicy: all-unauthenticated, which means that traffic is allowed by default and we don’t require to declare authorization policies associated to it:

kubectl apply -f - <<EOF
---
apiVersion: policy.linkerd.io/v1beta3
kind: Server
metadata:
  namespace: emojivoto
  name: web-http
spec:
  accessPolicy: all-unauthenticated
  podSelector:
    matchLabels:
      app: web-svc
  port: http
  proxyProtocol: HTTP/1
EOF

Now we can apply the HTTPLocalRateLimitPolicy resource pointing to that Server. For now, we’ll just set a limit of 4 RPS per identity:

kubectl apply -f - <<EOF
---
apiVersion: policy.linkerd.io/v1alpha1
kind: HTTPLocalRateLimitPolicy
metadata:
  namespace: emojivoto
  name: web-http
spec:
  targetRef:
    group: policy.linkerd.io
    kind: Server
    name: web-http
  identity:
    requestsPerSecond: 4
EOF

Sending requests

In the Ubuntu shell, issue 10 concurrent requests to web-svc.emojivoto:

root@client-xxx:/# results=$(for i in {1..10}; do curl -s -o /dev/null -w "%{http_code}\n" "http://web-svc.emojivoto" & done; wait)
root@client-xxx:/# echo $results
200 200 200 429 429 429 429 200 429 429

We see that only 4 requests were allowed. The requests that got rate-limited receive a response with a 429 HTTP status code.

Overrides

The former client had no identity as it was deployed in the default namespace, where workloads are not injected by default.

Now let’s create a new Ubuntu workload in the emojivoto namespace, which will be injected by default, and whose identity will be associated to the default ServiceAccount in the emojivoto namespace:

kubectl -n emojivoto create deployment client --image ubuntu -- bash -c "sleep infinity"
kubectl -n emojivoto exec -it client-xxx -c ubuntu -- bash
root@client-xxx:/# apt-get update && apt-get install -y curl

Before issuing requests, let’s expand the HTTPLocalRateLimitPolicy resource, adding an override for this specific client, that’ll allow it to issue requests up to 6 RPS:

kubectl apply -f - <<EOF
---
apiVersion: policy.linkerd.io/v1alpha1
kind: HTTPLocalRateLimitPolicy
metadata:
  namespace: emojivoto
  name: web-http
spec:
  targetRef:
    group: policy.linkerd.io
    kind: Server
    name: web-http
  identity:
    requestsPerSecond: 4
  overrides:
  - requestsPerSecond: 6
    clientRefs:
    - kind: ServiceAccount
      namespace: emojivoto
      name: default
EOF

And finally back in the shell we execute the requests:

root@client-xxx:/# results=$(for i in {1..10}; do curl -s -o /dev/null -w "%{http_code}\n" "http://web-svc.emojivoto" & done; wait)
root@client-xxx:/# echo $results
429 429 429 429 200 200 200 200 200 200

We see that now 6 requests were allowed. If we tried again with the former client, we could verify we would still be allowed to 4 requests only.