Use external rate limit service

  • deployment the Envoyproxy ratelimit service to kubernetes
  • deployment the redis to serve envoy proxy ratelimit
  • use Envoyproxy ratelimit serivce in envoy filter chains through grpc service
  • for every workloads create Envoyfilter rule

Deployment the envoy ratelimit service

  • the deployment.yaml to reference
 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: envoy-ratelimt
 5  namespace: istio-system
 6  labels:
 7    app: envoy-ratelimt
 8spec:
 9  replicas: 2
10  selector:
11    matchLabels:
12      app: envoy-ratelimt
13  template:
14    metadata:
15      creationTimestamp: null
16      labels:
17        app: envoy-ratelimt
18    spec:
19      volumes:
20        - name: config
21          configMap:
22            name: ratelimit-config
23            defaultMode: 420
24            optional: false
25      containers:
26        - name: ratelimit
27          image: >-
28                        envoyproxy/ratelimit:9d8d70a8
29          command:
30            - /bin/ratelimit
31          env:
32            - name: REDIS_SOCKET_TYPE
33              value: tcp
34            - name: REDIS_URL
35              value: redis-master:6379
36            - name: RUNTIME_ROOT
37              value: /data
38            - name: RUNTIME_SUBDIRECTORY
39              value: ratelimit
40            - name: RUNTIME_IGNOREDOTFILES
41              value: 'true'
42            - name: RUNTIME_WATCH_ROOT
43              value: 'false'
44            - name: USE_STATSD
45              value: 'false'
46            - name: LOG_LEVEL
47              value: info
48          resources:
49            limits:
50              cpu: 1024m
51              memory: 1Gi
52            requests:
53              cpu: 256m
54              memory: 256Mi
55          volumeMounts:
56            - name: config
57              mountPath: /data/ratelimit/config
58              mountPropagation: None
59          terminationMessagePath: /dev/termination-log
60          terminationMessagePolicy: File
61          imagePullPolicy: IfNotPresent
62      restartPolicy: Always
63  strategy:
64    type: RollingUpdate
65    rollingUpdate:
66      maxUnavailable: 25%
67      maxSurge: 25%
68  revisionHistoryLimit: 10
69  progressDeadlineSeconds: 600
  • the ratelimit-config configmap
 1apiVersion: v1
 2kind: ConfigMap
 3metadata:
 4  name: ratelimit-config
 5  namespace: istio-system 
 6data:
 7  config.yaml: |
 8        domain: envoy-ratelimit
 9        descriptors:
10        - key: FIFTY_REQ_PER_MINUTE
11          rate_limit:
12            unit: minute
13            requests_per_unit: 50
14        - key: FIVE_REQ_PER_SECOND
15          rate_limit:
16            unit: second
17            requests_per_unit: 5
18        - key: TEN_REQ_PER_SECOND
19          rate_limit:  
20            requests_per_unit: 10
21            unit: second
22        - key: TEN_REQ_PER_MINUTE
23          value: "x-minute-10"
24          rate_limit:  
25            requests_per_unit: 10
26            unit: minute
27        - key: TWENTY_REQ_PER_SECOND_BASE_PATH
28          rate_limit:
29            requests_per_unit: 20
30            unit: second
31          value: "/api/version"
32        - key: THREE_REQ_PER_SECOND_HEADER_MATCH
33          value: "get"
34          descriptors: 
35          - key: "HEADER_RANGE"
36            value: "x-second-3" 
37            rate_limit:
38                requests_per_unit: 3
39                unit: second        
  • create the ratelimit-svc service
 1apiVersion: v1
 2kind: Service
 3metadata:
 4  name: ratelimit-svc
 5  namespace: istio-system
 6status:
 7  loadBalancer: {}
 8spec:
 9  ports:
10    - name: grpc
11      protocol: TCP
12      port: 8081
13      targetPort: 8081
14    - name: http
15      protocol: TCP
16      port: 8080
17      targetPort: 8080
18  selector:
19    app: envoy-ratelimt
20  type: ClusterIP
21  sessionAffinity: None
22  ipFamilies:
23    - IPv4
24  ipFamilyPolicy: SingleStack
25  internalTrafficPolicy: Cluster

Use the ratelimit service for particular workload

  1apiVersion: networking.istio.io/v1alpha3
  2kind: EnvoyFilter
  3metadata:
  4  labels:
  5      app: demo-api-ratelimit
  6  name: demo-api-ratelimit-envoyfilter
  7  namespace: default
  8spec:
  9  workloadSelector:
 10    labels:
 11      app: demo-api
 12  configPatches:
 13  - applyTo: HTTP_FILTER
 14    match:
 15      context: SIDECAR_INBOUND
 16      listener:
 17          filterChain:
 18              filter:
 19                  name: envoy.filters.network.http_connection_manager
 20                  subFilter:
 21                      name: envoy.filters.http.router
 22    patch:
 23      operation: INSERT_BEFORE
 24      value:
 25        name: envoy.filters.http.ratelimit
 26        typed_config:
 27          "@type": "type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit"
 28          domain: hpa-ratelimit # must match domain in ratelimit ConfigMap
 29          failure_mode_deny: false # run plugin in fail-open mode, no limiting happens if ratelimit is unavailable
 30          enable_x_ratelimit_headers: DRAFT_VERSION_03
 31          disable_x_envoy_ratelimited_header: true
 32          rate_limit_service:
 33              grpc_service:
 34                  envoy_grpc:
 35                      cluster_name: rate_limit_service
 36                  timeout: 10s
 37              transport_api_version: V3
 38
 39  - applyTo: CLUSTER
 40    match:
 41      cluster:
 42      # this should be the ratelimit kubernetes service FQDN
 43          service: ratelimit-svc.istio-system.svc.cluster.local
 44    patch:
 45        # add a new cluster for rate limit service
 46        operation: ADD
 47        value:
 48            connect_timeout: 10s
 49            load_assignment:
 50              cluster_name: rate_limit_service
 51              endpoints:
 52                - lb_endpoints:
 53                    - endpoint:
 54                        address:
 55                          socket_address:
 56                            address: ratelimit-svc.istio-system.svc.cluster.local
 57                            port_value: 8081
 58            http2_protocol_options: {}
 59            lb_policy: ROUND_ROBIN
 60            name: rate_limit_service
 61            type: STRICT_DNS
 62
 63# the match rule reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-msg-config-route-v3-headermatcher
 64  - applyTo: VIRTUAL_HOST
 65    match:
 66       context: SIDECAR_INBOUND
 67      #  routeConfiguration:
 68      #     # portNumber: 80
 69      #    vhost:
 70      #      name: inbound|http|80 # port must be a port your Service is listening on
 71       routeConfiguration:
 72          vhost:
 73            name: "inbound|http|80"
 74            route:
 75              action: ANY
 76    patch:
 77      operation: MERGE
 78      value:
 79         rate_limits:
 80           - actions:
 81                - header_value_match:
 82                    descriptor_key: "TWENTY_REQ_PER_SECOND_BASE_PATH"
 83                    descriptor_value: "/api/version"
 84                    headers:
 85                      - name: :path
 86                        prefix_match: /api/version
 87           - actions:
 88                - request_headers:
 89                    header_name: ":path"
 90                    descriptor_key: "FIVE_REQ_PER_SECOND"
 91           - actions:
 92               - header_value_match:
 93                    descriptor_key: "TEN_REQ_PER_MINUTE"
 94                    descriptor_value: "x-minute-10"
 95                    headers:
 96                      - name: :method
 97                        prefix_match: GET
 98                      - name: x-minute-10
 99                        range_match:
100                          start: 100
101                          end: 200

Now use the local ratelimit is better

use istio CR to define the envoy proxy filter

  1# local rate limit reference to: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/local_rate_limit_filter
  2# configuration reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/local_ratelimit/v3/local_rate_limit.proto#envoy-v3-api-msg-extensions-filters-http-local-ratelimit-v3-localratelimit
  3apiVersion: networking.istio.io/v1alpha3
  4kind: EnvoyFilter
  5metadata:
  6  name: demo-api-localratelimit-envoyfilter
  7  namespace: default
  8spec:
  9  workloadSelector:
 10    labels:
 11      app: demo-api-df79124
 12  configPatches:
 13    - applyTo: HTTP_FILTER
 14      match:
 15        context: SIDECAR_INBOUND
 16        listener:
 17          filterChain:
 18            filter:
 19              name: "envoy.filters.network.http_connection_manager"
 20      patch:
 21        operation: INSERT_BEFORE
 22        value:
 23          name: envoy.filters.http.local_ratelimit
 24          typed_config:
 25            "@type": type.googleapis.com/udpa.type.v1.TypedStruct
 26            type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
 27            value:
 28              stat_prefix: demo-api
 29              enable_x_ratelimit_headers: DRAFT_VERSION_03
 30
 31    - applyTo: HTTP_ROUTE
 32      match:
 33        context: SIDECAR_INBOUND
 34        routeConfiguration:
 35          vhost:
 36            name: "inbound|http|80"
 37            route:
 38              action: ANY
 39      patch:
 40        operation: MERGE
 41        value:
 42          route:
 43            rate_limits:
 44            # The actions reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-msg-config-route-v3-ratelimit
 45              - actions:
 46                  - header_value_match:
 47                        descriptor_key: "TEN_REQ_PER_MINUTE"
 48                        descriptor_value: "x-minute-10"
 49                        headers:
 50                          - name: :method
 51                            prefix_match: GET
 52                          - name: x-minute-10
 53                            range_match:
 54                              start: 100
 55                              end: 200
 56              - actions:                
 57                  - query_parameter_value_match:
 58                        descriptor_key: "ONE_REQ_PER_SECOND"
 59                        descriptor_value: "OnePerSec"
 60                        query_parameters:
 61                          - name: is_office
 62                            present_match: true
 63
 64              - actions:
 65                    - request_headers:
 66                        header_name: ":path"
 67                        descriptor_key: "TEN_REQ_PER_SECOND"
 68
 69
 70          typed_per_filter_config:
 71            envoy.filters.http.local_ratelimit:
 72              "@type": type.googleapis.com/udpa.type.v1.TypedStruct
 73              type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
 74              value:
 75                stat_prefix: demo-api
 76                enable_x_ratelimit_headers: DRAFT_VERSION_03
 77                descriptors:
 78                 - entries:
 79                   - key: TEN_REQ_PER_SECOND
 80                     value: "/api/v2"
 81                   token_bucket:
 82                     max_tokens: 500
 83                     tokens_per_fill: 500
 84                     fill_interval: 60s
 85                 - entries:
 86                   - key: ONE_REQ_PER_SECOND
 87                     value: "OnePerSec"
 88                   token_bucket:
 89                      max_tokens: 60
 90                      tokens_per_fill: 60
 91                      fill_interval: 60s
 92                 - entries:
 93                   - key: TEN_REQ_PER_MINUTE
 94                     value: "x-minute-10"
 95                   token_bucket:
 96                     max_tokens: 10
 97                     tokens_per_fill: 10
 98                     fill_interval: 60s
 99                filter_enabled:
100                  runtime_key: local_rate_limit_enabled
101                  default_value:
102                    numerator: 100
103                    denominator: HUNDRED
104                filter_enforced:
105                  runtime_key: local_rate_limit_enforced
106                  default_value:
107                    numerator: 100
108                    denominator: HUNDRED
109                token_bucket:
110                  max_tokens: 1000
111                  tokens_per_fill: 1000
112                  fill_interval: 60s

Enable the statistics for rate limit of pod template

1template:
2  metadata:
3    annotations:
4          proxy.istio.io/config: |-
5            proxyStatsMatcher:
6              inclusionRegexps:
7              - ".*http_local_rate_limit.*"