Envoy で Google Cloud Armor のレート制限を構成する
このページでは、Cloud Armor を使用してサービス メッシュのグローバル サーバーサイド レート制限を構成する方法について説明します。この機能を使用すると、サービスに到着するすべてのトラフィックに公正なレート制限を適用できます。これにより、利用可能なサービスのキャパシティを公平に共有し、悪意のあるクライアントや不正な動作をするクライアントによるサービスの過負荷リスクを軽減できます。レート制限の詳細については、レート制限の概要をご覧ください。
Envoy 用に Google Kubernetes Engine(GKE)を構成する
始める前に
始める前に、次の API を有効にする必要があります。
container.googleapis.com
compute.googleapis.com
trafficdirector.googleapis.com
networkservices.googleapis.com
meshconfig.googleapis.com
monitoring.googleapis.com
次の Google Cloud CLI コマンドを使用すると、すべての API を有効にできます。
gcloud services enable \ container.googleapis.com \ compute.googleapis.com \ trafficdirector.googleapis.com \ networkservices.googleapis.com \ meshconfig.googleapis.com \ monitoring.googleapis.com
次に、このドキュメントで使用する環境変数を作成します。
export PROJECT_ID=PROJECT_ID export PROJECT_NUMBER="$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")" export CLUSTER=CLUSTER export ZONE=ZONE export MESH_NAME=MESH_NAME export MESH_URI=projects/${PROJECT_NUMBER}/locations/global/meshes/${MESH_NAME}
次の変数をプロジェクトの情報に置き換えます。
PROJECT_ID
は、実際のプロジェクト ID に置き換えます。ZONE
は、GKE クラスタを作成する予定のゾーンに置き換えます。CLUSTER
は、クラスタの名前に置き換えます。MESH_NAME
は、メッシュの名前に置き換えます。
GKE クラスタを作成する
次のコマンドを使用して、前のセクションで指定したゾーンに GKE クラスタを作成します。
gcloud container clusters create "CLUSTER" \ --zone="ZONE" \ --scopes="cloud-platform" \ --tags="allow-envoy-health-checks" \ --enable-ip-alias
新しいクラスタの認証情報を取得します。
gcloud container clusters get-credentials "CLUSTER" \ --zone="ZONE"
自動インジェクションを有効にする
次のコマンドを使用して、
MutatingWebhookConfiguration
リソースをクラスタに適用します。Pod が作成されると、クラスタ内アドミッション コントローラが呼び出され、マネージド サイドカー インジェクタに Envoy コンテナを Pod に追加するよう指示します。cat <<EOF | kubectl apply -f - apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: labels: app: sidecar-injector name: td-mutating-webhook webhooks: - admissionReviewVersions: - v1beta1 - v1 clientConfig: url: https://meshconfig.googleapis.com/v1internal/projects/PROJECT_ID/locations/ZONE/clusters/CLUSTER/channels/rapid/targets/${MESH_URI}:tdInject failurePolicy: Fail matchPolicy: Exact name: namespace.sidecar-injector.csm.io namespaceSelector: matchExpressions: - key: td-injection operator: Exists reinvocationPolicy: Never rules: - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods scope: '*' sideEffects: None timeoutSeconds: 30 EOF
デフォルトの名前空間についてのサイドカー インジェクションを有効にします。サイドカー インジェクタは、デフォルトの名前空間の下に作成された Pod にサイドカー コンテナを挿入します。
kubectl label namespace default td-injection=enabled
次のサービスの GKE 構成ファイルを
service_sample.yaml
として保存します。apiVersion: v1 kind: Service metadata: name: service-test annotations: cloud.google.com/neg: '{"exposed_ports":{"80":{"name": "rate-limit-demo-neg"}}}' spec: ports: - port: 80 name: service-test targetPort: 8000 selector: run: app1 type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: app1 labels: run: app1 spec: replicas: 1 selector: matchLabels: run: app1 template: metadata: labels: run: app1 annotations: cloud.google.com/proxyMetadata: '{"app": "rate-limit-demo"}' cloud.google.com/includeInboundPorts: "8000" cloud.google.com/sidecarProxyVersion: "1.34.1-gke.1" spec: containers: - image: mendhak/http-https-echo:37 name: app1 ports: - containerPort: 8000 env: - name: VALIDATION_NONCE value: "http" - name: HTTP_PORT value: "8000" securityContext: fsGroup: 1337
前のステップで作成したサービスのサンプルを適用します。
kubectl apply -f service_sample.yaml
次のクライアントの GKE 構成ファイルを
client_sample.yaml
として保存します。apiVersion: apps/v1 kind: Deployment metadata: labels: run: client name: load-generator spec: replicas: 1 selector: matchLabels: run: client template: metadata: labels: run: client spec: containers: - name: load-generator image: envoyproxy/nighthawk-dev command: ["/bin/sh", "-c"] args: ["echo 'Nighthawk client pod is running' && sleep infinity"] resources: requests: cpu: 200m memory: 256Mi limits: cpu: 1 memory: 512Mi securityContext: fsGroup: 1337
前のステップで作成したクライアントのサンプルを適用します。
kubectl apply -f client_sample.yaml
レート制限用に Cloud Service Mesh を設定する
このセクションの手順に沿って、レート制限用に Cloud Service Mesh を準備します。
Mesh
リソース仕様を作成し、mesh.yaml
というファイルに保存します。name: MESH_NAME interceptionPort: 15001
mesh.yaml 仕様を使用して
Mesh
リソースを作成します。gcloud network-services meshes import "MESH_NAME" \ --source=mesh.yaml \ --location=global
ヘルスチェックを作成します。
gcloud compute health-checks create http rate-limit-demo-hc \ --use-serving-port
ネットワーク内のインスタンスへの受信ヘルスチェック接続を許可するように、ファイアウォール ルールを作成します。
gcloud compute firewall-rules create rate-limit-demo-fw-allow-hc \ --action ALLOW \ --direction INGRESS \ --source-ranges 35.191.0.0/16,130.211.0.0/22 \ --target-tags allow-envoy-health-checks \ --rules tcp
INTERNAL_SELF_MANAGED
のロード バランシング方式でグローバル バックエンド サービスを作成し、ヘルスチェックを追加します。gcloud compute backend-services create rate-limit-demo-service \ --global \ --health-checks rate-limit-demo-hc \ --load-balancing-scheme INTERNAL_SELF_MANAGED
NEG
rate-limit-demo-neg
をバックエンド サービスに追加します。gcloud compute backend-services add-backend rate-limit-demo-service \ --global \ --network-endpoint-group rate-limit-demo-neg \ --network-endpoint-group-zone "ZONE" \ --balancing-mode RATE \ --max-rate-per-endpoint 5
HTTPRoute
仕様を作成し、http_route.yaml
というファイルに保存します。name: rate-limit-demo-http-route hostnames: - service-test - service-test:80 meshes: - projects/PROJECT_ID/locations/global/meshes/MESH_NAME rules: - action: destinations: - serviceName: "projects/PROJECT_ID/locations/global/backendServices/rate-limit-demo-service"
http_route.yaml
ファイルの仕様を使用して、HTTPRoute
リソースを作成します。gcloud network-services http-routes import rate-limit-demo-http-route \ --source=http_route.yaml \ --location=global
Envoy でレート制限を構成する
以降のセクションでは、サービス メッシュのサーバーサイド レート制限を構成する方法について説明します。最初のセクションでは、すべてのクライアントに 1 つのサーバーサイドのグローバル レート制限を設定する方法について説明します。2 番目のセクションでは、クライアントのグループごとに異なるレート制限を適用する方法について説明します。
サーバーサイドのグローバル レート制限を構成する
この例では、すべてのクライアントにレート制限を適用するサーバーサイドのレート制限ルールを 1 つ作成します。
rate-limit-policy.yaml
という名前の YAML ファイルで、タイプがCLOUD_ARMOR_INTERNAL_SERVICE
の Cloud Armor セキュリティ ポリシーを作成します。name: "rate-limit-policy" type: CLOUD_ARMOR_INTERNAL_SERVICE rules: - priority: 2147483647 match: config: srcIpRanges: ["*"] versionedExpr: SRC_IPS_V1 action: "fairshare" rateLimitOptions: rateLimitThreshold: count: 10000 intervalSec: 60 exceedAction: "deny(429)" conformAction: "allow" enforceOnKey: "ALL"
rate-limit-policy
という名前のセキュリティ ポリシーを作成します。gcloud beta compute security-policies create rate-limit-policy \ --global \ --file-name=rate-limit-policy.yaml
YAML ファイルで、前のステップで作成したセキュリティ ポリシーを参照するエンドポイント ポリシーを作成します。これらの例では、このファイルは
endpoints-policies.yaml
と呼ばれます。name: "rate-limit-ep" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: MATCH_ALL metadataLabels: - labelName: app labelValue: rate-limit-demo type: SIDECAR_PROXY securityPolicy: projects/PROJECT_ID/locations/global/securityPolicies/rate-limit-policy
rate-limit-ep
という名前のエンドポイント ポリシーを作成します。gcloud beta network-services endpoint-policies import rate-limit-ep \ --source=endpoints-policies.yaml \ --location=global
クライアントのグループごとに異なるサーバーサイドのレート制限を構成する
この例では、クライアントのグループごとに異なるレート制限のしきい値を適用する、サーバーサイドのレート制限ルールを複数作成します。
次のファイルで定義されているように、複数のレート制限ルールを含むタイプが
CLOUD_ARMOR_INTERNAL_SERVICE
の Cloud Armor セキュリティ ポリシーを作成します。これらの例では、このファイルはper-client-security-policy.yaml
と呼ばれます。name: "per-client-security-policy" type: CLOUD_ARMOR_INTERNAL_SERVICE rules: - priority: 0 match: expr: expression: "request.headers['user'] == 'demo'" action: "fairshare" rateLimitOptions: rateLimitThreshold: count: 1000 intervalSec: 60 exceedAction: "deny(429)" conformAction: "allow" enforceOnKey: "ALL" - priority: 2147483647 match: config: srcIpRanges: ["*"] versionedExpr: SRC_IPS_V1 action: "fairshare" rateLimitOptions: rateLimitThreshold: count: 10000 intervalSec: 60 exceedAction: "deny(429)" conformAction: "allow" enforceOnKey: "ALL"
このポリシーは、Cloud Service Mesh が 60 秒の時間内で 1,000 件を超えるリクエストを受信した場合、名前が
user
で値がdemo
の HTTP ヘッダーを含むリクエストにレート制限を適用します。この HTTP ヘッダーがないリクエストは、Cloud Service Mesh が 60 秒の時間内で 10,000 件を超えるリクエストを受信した場合にレート制限されます。次のコマンドを使用して、
per-client-security-policy
という名前のポリシーを作成します。gcloud beta compute security-policies create per-client-security-policy \ --global \ --file-name=per-client-security-policy.yaml
次のファイルで定義されているように、前のステップで作成したセキュリティ ポリシーを参照するエンドポイント ポリシーを作成します。この例では、このファイルは
per-client-endpoints-policies.yaml
と呼ばれます。name: "rate-limit-ep" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: MATCH_ALL metadataLabels: - labelName: app labelValue: rate-limit-demo type: SIDECAR_PROXY securityPolicy: projects/PROJECT_ID/locations/global/securityPolicies/per-client-security-policy
次のコマンドを使用して、
rate-limit-ep
という名前のエンドポイント ポリシーを作成します。gcloud beta network-services endpoint-policies import rate-limit-ep \ --source=per-client-endpoints-policies.yaml \ --location=global
設定を確認する
Nighthawk ロード テストツールを使用すると、トラフィックを生成してレート制限ルールが想定どおりに機能しているかどうかをテストできます。Nighthawk でトラフィックを生成するには、以下のコマンドを使用します。
kubectl exec -it deploy/load-generator -c load-generator -- \ nighthawk_client http://service-test \ --open-loop --no-default-failure-predicates \ --rps 60 \ --duration 360 \ --connections 10 \ --protocol http1 \ --request-header user:demo
次に、以下のコマンドを使用して Envoy デバッグログを有効にします。
kubectl exec -it deploy/app1 -c app1 -- wget -q -O - \ --post-data="" 'http://localhost:15000/logging?level=debug'
Envoy が管理サーバーに送信する使用状況レポートを表示するには、ログへのアクセスをご覧ください。
テスト結果から、以下のことが確認できます。
- レート制限が有効になるまでに約 5 分かかる。
- 初期ウォームアップ期間の後、Nighthawk クライアント出力の
benchmark.http_2xx
カウンタから 15~21 QPS が表示される。つまり、Cloud Armor は 1 分あたり約 1,000 件のリクエストを許可します。
Cloud Armor セキュリティ ポリシーのルールの有効性を確認するには、モニタリング ダッシュボードの表示をご覧ください。
レート制限を無効にする
レート制限は、次のいずれかの方法で無効にできます。
- レート制限ルールで構成したエンドポイント ポリシーとセキュリティ ポリシーを削除する。
- エンドポイント ポリシーを更新して
securityPolicies
フィールドを削除することで、セキュリティ ポリシーをエンドポイント ポリシーから切り離す。
以降のセクションでは、それぞれの方法を使用してレート制限を無効にする方法について説明します。
エンドポイント ポリシーとセキュリティ ポリシーを削除する
まず、以下の gcloud
コマンドを使用して、rate-limit-ep
という名前のエンドポイント ポリシーを削除します。このページの最初の例または 2 番目の例で指定された名前を使用した場合は、エンドポイント ポリシーの名前はそれぞれ endpoints-policies
または per-client-endpoints-policies
になります。
gcloud beta network-services endpoint-policies delete --location=global rate-limit-ep
次に、以下の gcloud
コマンドを使用してセキュリティ ポリシーを削除します。per-client-security-policy
は、セキュリティ ポリシーの名前に置き換えます。このページの最初の例または 2 番目の例で指定された名前を使用した場合は、セキュリティ ポリシーの名前がエンドポイント ポリシーと同じになります。
gcloud beta compute security-policies delete --global per-client-security-policy
セキュリティ ポリシーをエンドポイント ポリシーから切り離す
まず、endpoint-policy.yaml
ファイルを更新して securityPolcies
フィールドを削除します。
name: "rate-limit-ep" endpointMatcher: metadataLabelMatcher: metadataLabelMatchCriteria: MATCH_ALL metadataLabels: - labelName: app labelValue: rate-limit-demo type: SIDECAR_PROXY
次に、以下のコマンドを使用して、endpoint-policy.yaml
ファイルの変更内容で rate-limit-ep
という名前のエンドポイント ポリシーを更新します。
gcloud beta network-services endpoint-policies import rate-limit-ep \ --source=endpoints-policies.yaml \ --location=global