Увімкнення обмеження швидкості за допомогою Envoy
Ця задача показує, як використовувати вбудоване обмеження швидкості Envoy для динамічного обмеження трафіку до сервісу Istio. У цій задачі ви застосуєте глобальне обмеження швидкості для сервісу productpage
через вхідний шлюз, яке дозволяє 1 запит на хвилину для всіх екземплярів сервісу. Додатково, ви застосуєте локальне обмеження швидкості для кожного окремого екземпляра productpage
, яке дозволяє 4 запити на хвилину. Таким чином, ви забезпечите, що сервіс productpage
обробляє максимум 1 запит на хвилину через вхідний шлюз, але кожен екземпляр productpage
може обробляти до 4 запитів на хвилину, що дозволяє будь-який внутрішньомережевий трафік.
Перед тим як почати
Налаштуйте Istio в кластері Kubernetes, дотримуючись інструкцій з Посібника з установки.
Розгорніть демонстраційний застосунок Bookinfo.
Обмеження швидкості
Envoy підтримує два види обмеження швидкості: глобальне та локальне. Глобальне обмеження швидкості використовує глобальну службу обмеження швидкості gRPC для забезпечення обмеження швидкості для всієї мережі. Локальне обмеження швидкості використовується для обмеження кількості запитів для кожного екземпляра сервісу. Локальне обмеження швидкості можна використовувати разом з глобальним обмеженням швидкості для зменшення навантаження на глобальну службу обмеження швидкості.
У цій задачі ви налаштуєте Envoy для обмеження швидкості трафіку до конкретного шляху сервісу, використовуючи як глобальні, так і локальні обмеження швидкості.
Глобальне обмеження швидкості
Envoy можна використовувати для налаштування глобальних обмежень швидкості для вашої мережі. Глобальне обмеження швидкості в Envoy використовує API gRPC для запиту квоти від служби обмеження швидкості. Приклад реалізації API, написаний на Go з бекендом Redis, використовується нижче.
Використовуйте наступний configmap для налаштування референсної реалізації для обмеження швидкості запитів до шляху
/productpage
на 1 запит/хв, значенняapi
для наступного розширеного прикладу і всі інші запити на 100 запитів/хв.$ kubectl apply -f - <<EOF apiVersion: v1 kind: ConfigMap metadata: name: ratelimit-config data: config.yaml: | domain: ratelimit descriptors: - key: PATH value: "/productpage" rate_limit: unit: minute requests_per_unit: 1 - key: PATH value: "api" rate_limit: unit: minute requests_per_unit: 2 - key: PATH rate_limit: unit: minute requests_per_unit: 100 EOF
Створіть глобальну службу обмеження швидкості, яка реалізує протокол служби обмеження швидкості Envoy. Для прикладу конфігурації можна скористатися цим посиланням, яке базується на реалізації, наданій Envoy.
$ kubectl apply -f @samples/ratelimit/rate-limit-service.yaml@
Застосуйте
EnvoyFilter
доingressgateway
, щоб увімкнути глобальне обмеження швидкості, використовуючи глобальний фільтр обмеження швидкості Envoy.Патч вставляє
envoy.filters.http.ratelimit
глобальний фільтр envoy у ланцюгHTTP_FILTER
. Полеrate_limit_service
вказує на зовнішню службу обмеження швидкості,outbound|8081||ratelimit.default.svc.cluster.local
у цьому випадку.$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: filter-ratelimit namespace: istio-system spec: workloadSelector: # вибрати за міткою в тому самому просторі імен labels: istio: ingressgateway configPatches: # Конфігурація Envoy, яку ви хочете змінити - applyTo: HTTP_FILTER match: context: GATEWAY listener: filterChain: filter: name: "envoy.filters.network.http_connection_manager" subFilter: name: "envoy.filters.http.router" patch: operation: INSERT_BEFORE # Додає фільтр обмеження швидкості Envoy до ланцюжка фільтрів HTTP. value: name: envoy.filters.http.ratelimit typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit # домен може бути будь-яким! Порівняйте його з конфігом сервісу ratelimter domain: ratelimit failure_mode_deny: true timeout: 10s rate_limit_service: grpc_service: envoy_grpc: cluster_name: outbound|8081||ratelimit.default.svc.cluster.local authority: ratelimit.default.svc.cluster.local transport_api_version: V3 EOF
Застосуйте інший
EnvoyFilter
доingressgateway
, який визначає конфігурацію маршруту, на якому слід обмежити швидкість. Це додає дії обмеження швидкості для будь-якого маршруту з віртуального хосту з назвоюbookinfo.com:80
.$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: filter-ratelimit-svc namespace: istio-system spec: workloadSelector: labels: istio: ingressgateway configPatches: - applyTo: VIRTUAL_HOST match: context: GATEWAY routeConfiguration: vhost: name: "" route: action: ANY patch: operation: MERGE # Applies the rate limit rules. value: rate_limits: - actions: # any actions in here - request_headers: header_name: ":path" descriptor_key: "PATH" EOF
Глобальне обмеження швидкості, розширений випадок
Цей приклад використовує regex для порівняння /api/*
uri
і визначає дію обмеження швидкості, яка вставляється на рівні маршруту, використовуючи імʼя http VirtualService. Значення PATH api
, вставлене в попередньому прикладі, стає актуальним.
Змініть VirtualService так, щоб префікс
/api/v1/products
був переміщений на маршрут з імʼямapi
:$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: bookinfo spec: gateways: - bookinfo-gateway hosts: - '*' http: - match: - uri: exact: /productpage - uri: prefix: /static - uri: exact: /login - uri: exact: /logout route: - destination: host: productpage port: number: 9080 - match: - uri: prefix: /api/v1/products route: - destination: host: productpage port: number: 9080 name: api EOF
Застосуйте EnvoyFilter, щоб додати дію обмеження швидкості на рівні маршруту для будь-якого продукту з 1 до 99:
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: filter-ratelimit-svc-api namespace: istio-system spec: workloadSelector: labels: istio: ingressgateway configPatches: - applyTo: HTTP_ROUTE match: context: GATEWAY routeConfiguration: vhost: name: "*:8080" route: name: "api" patch: operation: MERGE value: route: rate_limits: - actions: - header_value_match: descriptor_key: "PATH" descriptor_value: "api" headers: - name: ":path" safe_regex_match: google_re2: {} regex: "/api/v1/products/[1-9]{1,2}" EOF
Локальне обмеження швидкості
Envoy підтримує локальне обмеження швидкості для зʼєднань L4 і HTTP запитів. Це дозволяє застосовувати обмеження швидкості на рівні екземпляра, без виклику будь-якого іншого сервісу.
Наступний EnvoyFilter
включає локальне обмеження швидкості для будь-якого трафіку через сервіс productpage
. Патч HTTP_FILTER
вставляє envoy.filters.http.local_ratelimit
локальний envoy filter у фільтр-ланцюг HTTP зʼєднання менеджера. Локальний фільтр обмеження швидкості кошик з токенами налаштовано на дозвіл 4 запитів/хв. Фільтр також налаштований на додавання заголовка x-local-rate-limit
до запитів, які заблоковані.
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: filter-local-ratelimit-svc
namespace: istio-system
spec:
workloadSelector:
labels:
app: productpage
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.local_ratelimit
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value:
stat_prefix: http_local_rate_limiter
token_bucket:
max_tokens: 4
tokens_per_fill: 4
fill_interval: 60s
filter_enabled:
runtime_key: local_rate_limit_enabled
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
runtime_key: local_rate_limit_enforced
default_value:
numerator: 100
denominator: HUNDRED
response_headers_to_add:
- append: false
header:
key: x-local-rate-limit
value: 'true'
EOF
Вищезазначена конфігурація застосовує локальне обмеження швидкості до всіх vhosts/routes. Альтернативно, ви можете обмежити його до конкретного маршруту.
Наступний EnvoyFilter
включає локальне обмеження швидкості для будь-якого трафіку на порт 9080 сервісу productpage
. На відміну від попередньої конфігурації, в патчі HTTP_FILTER
не включено token_bucket
. token_bucket
визначено в другому патчі (HTTP_ROUTE
), який включає typed_per_filter_config
для фільтра envoy.filters.http.local_ratelimit
, для маршрутів до віртуального хоста inbound|http|9080
.
$ kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: filter-local-ratelimit-svc
namespace: istio-system
spec:
workloadSelector:
labels:
app: productpage
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.local_ratelimit
typed_config:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value:
stat_prefix: http_local_rate_limiter
- applyTo: HTTP_ROUTE
match:
context: SIDECAR_INBOUND
routeConfiguration:
vhost:
name: "inbound|http|9080"
route:
action: ANY
patch:
operation: MERGE
value:
typed_per_filter_config:
envoy.filters.http.local_ratelimit:
"@type": type.googleapis.com/udpa.type.v1.TypedStruct
type_url: type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
value:
stat_prefix: http_local_rate_limiter
token_bucket:
max_tokens: 4
tokens_per_fill: 4
fill_interval: 60s
filter_enabled:
runtime_key: local_rate_limit_enabled
default_value:
numerator: 100
denominator: HUNDRED
filter_enforced:
runtime_key: local_rate_limit_enforced
default_value:
numerator: 100
denominator: HUNDRED
response_headers_to_add:
- append: false
header:
key: x-local-rate-limit
value: 'true'
EOF
Перевірка результатів
Перевірка глобального обмеження швидкості
Надішліть трафік до застосунку Bookinfo. Відвідайте http://$GATEWAY_URL/productpage
у вашому вебоглядачі або виконайте наступну команду:
$ for i in {1..2}; do curl -s "http://$GATEWAY_URL/productpage" -o /dev/null -w "%{http_code}\n"; sleep 3; done
200
429
$ for i in {1..3}; do curl -s "http://$GATEWAY_URL/api/v1/products/${i}" -o /dev/null -w "%{http_code}\n"; sleep 3; done
200
200
429
Для /productpage
ви побачите, що перший запит проходить, але кожен наступний запит протягом хвилини отримує відповідь 429. А для /api/v1/products/*
потрібно буде зробити два запити, з будь-яким числом між 1 і 99, поки не отримаєте відповідь 429 протягом хвилини.
Перевірка локального обмеження швидкості
Хоча глобальне обмеження швидкості на шлюзі вхідних запитів обмежує запити до сервісу productpage
до 1 запиту/хв, локальне обмеження швидкості для екземплярів productpage
дозволяє 4 запити/хв. Щоб підтвердити це, надішліть внутрішні запити до productpage
з podʼа ratings
, використовуючи наступну команду curl
:
$ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- bash -c 'for i in {1..5}; do curl -s productpage:9080/productpage -o /dev/null -w "%{http_code}\n"; sleep 1; done'
200
200
200
200
429
Ви повинні побачити не більше 4 запитів/хв, які проходять через кожен екземпляр productpage
.
Очищення
$ kubectl delete envoyfilter filter-ratelimit -nistio-system
$ kubectl delete envoyfilter filter-ratelimit-svc -nistio-system
$ kubectl delete envoyfilter filter-ratelimit-svc-api -nistio-system
$ kubectl delete envoyfilter filter-local-ratelimit-svc -nistio-system
$ kubectl delete cm ratelimit-config
$ kubectl delete -f @samples/ratelimit/rate-limit-service.yaml@