Envoy を使用したレート制限の有効化

このタスクでは、Envoy のネイティブレート制限を使用して、Istio サービスへのトラフィックを動的に制限する方法を示します。このタスクでは、サービス全体のすべてのインスタンスに対して 1 分あたり 1 リクエストを許可する、イングレスゲートウェイを介したproductpageサービスに対するグローバルレート制限を適用します。さらに、1 分あたり 4 リクエストを許可する、個々のproductpageインスタンスごとのローカルレート制限を適用します。このようにして、productpageサービスがイングレスゲートウェイを介して 1 分あたり最大 1 リクエストを処理することを保証しますが、各productpageインスタンスは最大 1 分あたり 4 リクエストを処理でき、メッシュ内のすべてのトラフィックに対応できます。

開始する前に

  1. インストールガイドの手順に従って、Kubernetes クラスターに Istio をセットアップします。

  2. Bookinfo サンプルアプリケーションをデプロイします。

レート制限

Envoy は、グローバルとローカルの2種類のレート制限をサポートしています。グローバルレート制限は、メッシュ全体のレート制限を提供するためにグローバル gRPC レート制限サービスを使用します。ローカルレート制限は、サービスインスタンスごとのリクエストレートを制限するために使用されます。ローカルレート制限は、グローバルレート制限サービスへの負荷を軽減するために、グローバルレート制限と組み合わせて使用できます。

このタスクでは、グローバルとローカルの両方のレート制限を使用して、サービスへの特定のパスへのトラフィックをレート制限するように Envoy を構成します。

グローバルレート制限

Envoy は、メッシュのグローバルレート制限を設定するために使用できます。Envoy におけるグローバルレート制限は、レート制限サービスからのクォータを要求するために gRPC API を使用します。以下では、Redis バックエンドを使用した Go で記述された API のリファレンス実装を使用します。

  1. 次の ConfigMap を使用して、パス /productpage へのリクエストを 1 req/min、後続の高度な例で使用する値 api、その他すべてのリクエストを 100 req/min にレート制限するようにリファレンス実装を構成します。

    $ 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
    
  2. Envoy のレート制限サービスプロトコルを実装するグローバルレート制限サービスを作成します。リファレンスとして、Envoy が提供するリファレンス実装に基づいたデモ構成はこちらにあります。

    Zip
    $ kubectl apply -f @samples/ratelimit/rate-limit-service.yaml@
    
  3. ingressgatewayEnvoyFilter を適用して、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:
        # select by label in the same namespace
        labels:
          istio: ingressgateway
      configPatches:
        # The Envoy config you want to modify
        - 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
            # Adds the Envoy Rate Limit Filter in HTTP filter chain.
            value:
              name: envoy.filters.http.ratelimit
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
                # domain can be anything! Match it to the ratelimter service config
                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
    
  4. レート制限を適用するルーティング構成を定義する別の EnvoyFilteringressgateway に適用します。これにより、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
    

グローバルレート制限の高度なケース

この例では、/api/* uri に一致させるために正規表現を使用し、VirtualService http 名を使用してルートレベルで挿入されるレート制限アクションを定義します。前の例で挿入された PATH 値 api がここで重要になります。

  1. プレフィックス /api/v1/productsapi というルートに移動するように VirtualService を変更します。

    $ 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
    
  2. 1から99の任意の製品について、ルートレベルでレート制限アクションを追加する EnvoyFilter を適用します。

    $ 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 フィルターを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

上記の構成は、すべての仮想ホスト/ルートにローカルレート制限を適用します。あるいは、特定のルートに制限することもできます。

次の EnvoyFilter は、productpage サービスのポート 9080 へのすべてのトラフィックに対してローカルレート制限を有効にします。前の構成とは異なり、HTTP_FILTER パッチには token_bucket は含まれていません。token_bucket は、代わりに、仮想ホスト inbound|http|9080 へのルートに対して、envoy.filters.http.local_ratelimit ローカル Envoy フィルターの typed_per_filter_config を含む2番目(HTTP_ROUTE)のパッチで定義されています。

$ 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 サンプルにトラフィックを送信します。Webブラウザーで 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 の場合、最初の要求は通過しますが、1分以内の後続のすべての要求は429応答を受け取ります。また、/api/v1/products/* の場合は、1分以内に429応答を受け取るまで、1〜99の間の任意の数を使用して2回ヒットする必要があります。

ローカルレート制限の検証

ingress gateway のグローバルレート制限では productpage サービスへのリクエストを 1 req/min に制限していますが、productpage インスタンスのローカルレート制限では 4 req/min が許可されています。これを確認するには、次の curl コマンドを使用して、ratings ポッドから内部 productpage リクエストを送信します。

$ 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

productpage インスタンスごとに、4 req/min を超えるリクエストは通過しないはずです。

クリーンアップ

Zip
$ 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@
この情報は役立ちましたか?
改善のためのご提案はありますか?

ご意見ありがとうございました!