From fa6277cea8980c15d9c4f77d23424452e229aef3 Mon Sep 17 00:00:00 2001 From: Yuki Sawa Date: Thu, 3 Sep 2020 09:38:45 -0700 Subject: [PATCH 1/5] Add full ratelimit test env docker-compose Signed-off-by: Yuki Sawa --- README.md | 22 ++++-- docker-compose-example.yml | 89 +++++++++++++++++++++++ examples/envoy/mock.yaml | 34 +++++++++ examples/envoy/proxy.yaml | 97 ++++++++++++++++++++++++++ examples/ratelimit/config/example.yaml | 26 +++++++ 5 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 docker-compose-example.yml create mode 100644 examples/envoy/mock.yaml create mode 100644 examples/envoy/proxy.yaml create mode 100644 examples/ratelimit/config/example.yaml diff --git a/README.md b/README.md index e2f45e36f..cadb555e1 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,20 @@ If you want to run with [two redis instances](#two-redis-instances), you will ne the docker-compose.yaml file to run a second redis container, and change the environment variables as explained in the [two redis instances](#two-redis-instances) section. +## Full test environment +To run a fully configured environment to demo Envoy based rate limiting, run: +```bash +docker-compose -f docker-compose-example.yaml up +``` +This will run ratelimit, redis, prom-statsd-exporter and two Envoy containers such that you can demo rate limiting by hitting the below endpoints. +```bash +curl localhost:8888/test +curl localhost:8888/header -H "foo: foo" # Header based +curl localhost:8888/twoheader -H "foo: foo" -H "bar: bar" # Two headers +curl localhost:8888/twoheader -H "foo: foo" -H "bar: banned" # Ban a particular header value +``` +Edit `examples/ratelimit/config/example.yaml` to test different rate limit configs. Hot reloading is enabled. + # Configuration ## The configuration format @@ -325,7 +339,7 @@ There are two methods for triggering a configuration reload: 1. Symlink RUNTIME_ROOT to a different directory. 2. Update the contents inside `RUNTIME_ROOT/RUNTIME_SUBDIRECTORY/config/` directly. -The former is the default behavior. To use the latter method, set the `RUNTIME_WATCH_ROOT` environment variable to `false`. +The former is the default behavior. To use the latter method, set the `RUNTIME_WATCH_ROOT` environment variable to `false`. For more information on how runtime works you can read its [README](https://github.com/lyft/goruntime). @@ -377,7 +391,7 @@ The ratelimit service listens to HTTP 1.1 (by default on port 8080) with two end ## /json endpoint -Takes an HTTP POST with a JSON body of the form e.g. +Takes an HTTP POST with a JSON body of the form e.g. ```json { "domain": "dummy", @@ -389,7 +403,7 @@ Takes an HTTP POST with a JSON body of the form e.g. ] } ``` -The service will return an http 200 if this request is allowed (if no ratelimits exceeded) or 429 if one or more +The service will return an http 200 if this request is allowed (if no ratelimits exceeded) or 429 if one or more ratelimits were exceeded. The response is a RateLimitResponse encoded with @@ -432,7 +446,7 @@ You can specify the debug port with the `DEBUG_PORT` environment variable. It de # Local Cache -Ratelimit optionally uses [freecache](https://github.com/coocood/freecache) as its local caching layer, which stores the over-the-limit cache keys, and thus avoids reading the +Ratelimit optionally uses [freecache](https://github.com/coocood/freecache) as its local caching layer, which stores the over-the-limit cache keys, and thus avoids reading the redis cache again for the already over-the-limit keys. The local cache size can be configured via `LocalCacheSizeInBytes` in the [settings](https://github.com/envoyproxy/ratelimit/blob/master/src/settings/settings.go). If `LocalCacheSizeInBytes` is 0, local cache is disabled. diff --git a/docker-compose-example.yml b/docker-compose-example.yml new file mode 100644 index 000000000..12dd8b980 --- /dev/null +++ b/docker-compose-example.yml @@ -0,0 +1,89 @@ +version: "3" +services: + redis: + image: redis:alpine + expose: + - 6379 + ports: + - 6379:6379 + networks: + - ratelimit-network + + statsd: + image: prom/statsd-exporter:v0.12.2 + expose: + - 9125 + ports: + - 9125:9125 + networks: + - ratelimit-network + + ratelimit: + image: envoyproxy/ratelimit:master + command: /bin/ratelimit + ports: + - 8080:8080 + - 8081:8081 + - 6070:6070 + depends_on: + - redis + - statsd + networks: + - ratelimit-network + volumes: + - ./examples/ratelimit/config:/data/ratelimit/config + environment: + - USE_STATSD=true + - STATSD_HOST=statsd + - STATSD_PORT=9125 + - LOG_LEVEL=debug + - REDIS_SOCKET_TYPE=tcp + - REDIS_URL=redis:6379 + - RUNTIME_ROOT=/data + - RUNTIME_SUBDIRECTORY=ratelimit + - RUNTIME_WATCH_ROOT=false + + envoy-proxy: + image: envoyproxy/envoy:v1.14.4 + entrypoint: "/usr/local/bin/envoy" + command: + - "--service-node proxy" + - "--service-cluster proxy" + - "--config-path /etc/envoy/envoy.yaml" + - "--concurrency 1" + - "--mode serve" + - "--log-level info" +# - "--component-log-level pool:info,upstream:info,connection:info,config:debug,router:debug" + volumes: + - ./examples/envoy/proxy.yaml:/etc/envoy/envoy.yaml + networks: + - ratelimit-network + expose: + - "8888" + - "8001" + ports: + - "8888:8888" + - "8001:8001" + + envoy-mock: + image: envoyproxy/envoy:v1.14.4 + entrypoint: "/usr/local/bin/envoy" + command: + - "--service-node mock" + - "--service-cluster mock" + - "--config-path /etc/envoy/envoy.yaml" + - "--concurrency 1" + - "--mode serve" + - "--log-level info" +# - "--component-log-level pool:info,upstream:info,connection:info,config:debug" + volumes: + - ./examples/envoy/mock.yaml:/etc/envoy/envoy.yaml + networks: + - ratelimit-network + expose: + - "9999" + ports: + - "9999:9999" + +networks: + ratelimit-network: diff --git a/examples/envoy/mock.yaml b/examples/envoy/mock.yaml new file mode 100644 index 000000000..bd85fc3d2 --- /dev/null +++ b/examples/envoy/mock.yaml @@ -0,0 +1,34 @@ +static_resources: + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 9999 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress + route_config: + name: ingress + virtual_hosts: + - name: backend + domains: + - "*" + routes: + - match: + prefix: "/" + direct_response: + status: "200" + body: + inline_string: "Hello World" + http_filters: + - name: envoy.router + config: {} +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 diff --git a/examples/envoy/proxy.yaml b/examples/envoy/proxy.yaml new file mode 100644 index 000000000..293af2288 --- /dev/null +++ b/examples/envoy/proxy.yaml @@ -0,0 +1,97 @@ +admin: + access_log_path: "/dev/null" + address: + socket_address: + address: 0.0.0.0 + port_value: 8001 +static_resources: + clusters: + - name: ratelimit + type: STRICT_DNS + connect_timeout: 1s + lb_policy: ROUND_ROBIN + protocol_selection: USE_CONFIGURED_PROTOCOL + http2_protocol_options: {} + load_assignment: + cluster_name: ratelimit + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: ratelimit + port_value: 8081 + - name: mock + connect_timeout: 1s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: mock + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: envoy-mock + port_value: 9999 + listeners: + - address: + socket_address: + address: 0.0.0.0 + port_value: 8888 + filter_chains: + - filters: + - name: envoy.http_connection_manager + config: + codec_type: auto + stat_prefix: ingress + http_filters: + - name: envoy.rate_limit + config: + domain: rl + request_type: external + stage: 0 + rate_limited_as_resource_exhausted: true + failure_mode_deny: false + rate_limit_service: + grpc_service: + envoy_grpc: + cluster_name: ratelimit + - name: envoy.router + config: {} + route_config: + name: route + virtual_hosts: + - name: backend + domains: + - "*" + routes: + - match: + prefix: /test + route: + cluster: mock + rate_limits: + - actions: + - source_cluster: {} + - destination_cluster: {} + - match: + prefix: /header + route: + cluster: mock + rate_limits: + - actions: + - request_headers: + header_name: "foo" + descriptor_key: "foo" + - match: + prefix: /twoheader + route: + cluster: mock + rate_limits: + - actions: + - request_headers: + header_name: "foo" + descriptor_key: "foo" + - request_headers: + header_name: "bar" + descriptor_key: "bar" diff --git a/examples/ratelimit/config/example.yaml b/examples/ratelimit/config/example.yaml new file mode 100644 index 000000000..a1570f174 --- /dev/null +++ b/examples/ratelimit/config/example.yaml @@ -0,0 +1,26 @@ +--- +domain: rl +descriptors: + - key: source_cluster + value: proxy + descriptors: + - key: destination_cluster + value: mock + rate_limit: + unit: minute + requests_per_unit: 1 + - key: foo + value: foo + rate_limit: + unit: minute + requests_per_unit: 2 + descriptors: + - key: bar + rate_limit: + unit: minute + requests_per_unit: 3 + - key: bar + value: banned + rate_limit: + unit: minute + requests_per_unit: 0 From 40fcb648e5d6c5826533093ceeadb8e29d56265a Mon Sep 17 00:00:00 2001 From: Yuki Sawa Date: Thu, 3 Sep 2020 09:41:41 -0700 Subject: [PATCH 2/5] Make ratelimit container wait till binary is ready to run Signed-off-by: Yuki Sawa --- docker-compose.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 51360d361..ac1ab9063 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,7 +29,8 @@ services: ratelimit: image: alpine:3.6 - command: /usr/local/bin/ratelimit + command: > + sh -c "until test -f /usr/local/bin/ratelimit; do sleep 5; done; /usr/local/bin/ratelimit" ports: - 8080:8080 - 8081:8081 From c6556502fec8705182c4d70497e851d2b09dad2e Mon Sep 17 00:00:00 2001 From: Yuki Sawa Date: Thu, 3 Sep 2020 09:47:57 -0700 Subject: [PATCH 3/5] clean up Signed-off-by: Yuki Sawa --- README.md | 1 + docker-compose-example.yml | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index cadb555e1..040df6b82 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ - [Deprecation Schedule](#deprecation-schedule) - [Building and Testing](#building-and-testing) - [Docker-compose setup](#docker-compose-setup) + - [Full test environment](#full-test-environment) - [Configuration](#configuration) - [The configuration format](#the-configuration-format) - [Definitions](#definitions) diff --git a/docker-compose-example.yml b/docker-compose-example.yml index 12dd8b980..be8057c45 100644 --- a/docker-compose-example.yml +++ b/docker-compose-example.yml @@ -53,7 +53,6 @@ services: - "--concurrency 1" - "--mode serve" - "--log-level info" -# - "--component-log-level pool:info,upstream:info,connection:info,config:debug,router:debug" volumes: - ./examples/envoy/proxy.yaml:/etc/envoy/envoy.yaml networks: @@ -75,7 +74,6 @@ services: - "--concurrency 1" - "--mode serve" - "--log-level info" -# - "--component-log-level pool:info,upstream:info,connection:info,config:debug" volumes: - ./examples/envoy/mock.yaml:/etc/envoy/envoy.yaml networks: From 3b7f59bfda41208a6572bac19447d431ea6690dd Mon Sep 17 00:00:00 2001 From: Yuki Sawa Date: Thu, 3 Sep 2020 09:53:29 -0700 Subject: [PATCH 4/5] Add details to README Signed-off-by: Yuki Sawa --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 040df6b82..db455cd5d 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,8 @@ curl localhost:8888/twoheader -H "foo: foo" -H "bar: banned" # Ban a particular ``` Edit `examples/ratelimit/config/example.yaml` to test different rate limit configs. Hot reloading is enabled. +The descriptors in `example.yaml` and the actions in `examples/envoy/proxy.yaml` should give you a good idea on how to configure rate limits. + # Configuration ## The configuration format From 0d5a3d0c3fc30318d3f0ea18b8e31fa487a0ecd9 Mon Sep 17 00:00:00 2001 From: Yuki Sawa Date: Fri, 4 Sep 2020 10:36:40 -0700 Subject: [PATCH 5/5] Update images to latest. Add 1 more RL example Signed-off-by: Yuki Sawa --- README.md | 1 + docker-compose-example.yml | 6 +++--- examples/envoy/proxy.yaml | 7 +++++++ examples/ratelimit/config/example.yaml | 5 ++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index db455cd5d..304e835d2 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ This will run ratelimit, redis, prom-statsd-exporter and two Envoy containers su curl localhost:8888/test curl localhost:8888/header -H "foo: foo" # Header based curl localhost:8888/twoheader -H "foo: foo" -H "bar: bar" # Two headers +curl localhost:8888/twoheader -H "foo: foo" -H "baz: baz" curl localhost:8888/twoheader -H "foo: foo" -H "bar: banned" # Ban a particular header value ``` Edit `examples/ratelimit/config/example.yaml` to test different rate limit configs. Hot reloading is enabled. diff --git a/docker-compose-example.yml b/docker-compose-example.yml index be8057c45..f96879ee4 100644 --- a/docker-compose-example.yml +++ b/docker-compose-example.yml @@ -10,7 +10,7 @@ services: - ratelimit-network statsd: - image: prom/statsd-exporter:v0.12.2 + image: prom/statsd-exporter:v0.18.0 expose: - 9125 ports: @@ -44,7 +44,7 @@ services: - RUNTIME_WATCH_ROOT=false envoy-proxy: - image: envoyproxy/envoy:v1.14.4 + image: envoyproxy/envoy-dev:latest entrypoint: "/usr/local/bin/envoy" command: - "--service-node proxy" @@ -65,7 +65,7 @@ services: - "8001:8001" envoy-mock: - image: envoyproxy/envoy:v1.14.4 + image: envoyproxy/envoy-dev:latest entrypoint: "/usr/local/bin/envoy" command: - "--service-node mock" diff --git a/examples/envoy/proxy.yaml b/examples/envoy/proxy.yaml index 293af2288..bb45503f9 100644 --- a/examples/envoy/proxy.yaml +++ b/examples/envoy/proxy.yaml @@ -95,3 +95,10 @@ static_resources: - request_headers: header_name: "bar" descriptor_key: "bar" + - actions: + - request_headers: + header_name: "foo" + descriptor_key: "foo" + - request_headers: + header_name: "baz" + descriptor_key: "baz" diff --git a/examples/ratelimit/config/example.yaml b/examples/ratelimit/config/example.yaml index a1570f174..03e2f7839 100644 --- a/examples/ratelimit/config/example.yaml +++ b/examples/ratelimit/config/example.yaml @@ -10,7 +10,6 @@ descriptors: unit: minute requests_per_unit: 1 - key: foo - value: foo rate_limit: unit: minute requests_per_unit: 2 @@ -24,3 +23,7 @@ descriptors: rate_limit: unit: minute requests_per_unit: 0 + - key: baz + rate_limit: + unit: second + requests_per_unit: 1