使用 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 叢集

  1. 使用下列指令,在上一節指定的可用區中建立 GKE 叢集:

     gcloud container clusters create "CLUSTER" \
         --zone="ZONE" \
         --scopes="cloud-platform" \
         --tags="allow-envoy-health-checks" \
         --enable-ip-alias
    
  2. 取得新叢集的憑證:

     gcloud container clusters get-credentials "CLUSTER" \
         --zone="ZONE"
    

啟用自動插入功能

  1. 使用下列指令,將 MutatingWebhookConfiguration 資源套用至叢集。建立 Pod 時,系統會叫用叢集內許可控制器,並指示受管理 Sidecar 注入器將 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
    
  2. 為預設命名空間啟用補充資訊植入功能。補充資訊注入器會為在預設命名空間下建立的 Pod 注入補充資訊容器。

    kubectl label namespace default td-injection=enabled
    
  3. 將下列服務的 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
    
  4. 套用您在上一個步驟中建立的服務範例:

    kubectl apply -f service_sample.yaml
    
  5. 將下列用戶端 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
    
  6. 套用您在上一步驟中建立的用戶端範例:

    kubectl apply -f client_sample.yaml
    

設定 Cloud Service Mesh 的速率限制

請按照本節的步驟,為 Cloud Service Mesh 準備速率限制。

  1. 建立 Mesh 資源規格,並儲存至名為 mesh.yaml 的檔案:

    name: MESH_NAME
    interceptionPort: 15001
    
  2. 使用 mesh.yaml 規格建立 Mesh 資源。

      gcloud network-services meshes import "MESH_NAME" \
          --source=mesh.yaml \
          --location=global
    
  3. 建立健康狀態檢查:

      gcloud compute health-checks create http rate-limit-demo-hc \
          --use-serving-port
    
  4. 建立防火牆規則,允許傳入的健康狀態檢查連線抵達您網路中的執行個體。

      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
    
  5. 使用 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
    
  6. 將 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
    
  7. 建立 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"
    
  8. 使用 http_route.yaml 檔案中的規格建立 HTTPRoute 資源。

      gcloud network-services http-routes import rate-limit-demo-http-route \
          --source=http_route.yaml \
          --location=global
    

使用 Envoy 設定頻率限制

下列各節說明如何為服務網格設定伺服器端速率限制。第一個部分說明如何為所有用戶端設定一個伺服器端全域速率限制,第二個部分則說明如何為不同用戶端群組強制執行不同的速率限制。

設定伺服器端全域速率限制

在本例中,您將建立一項伺服器端速率限制規則,對所有用戶端強制執行速率限制。

  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"
    
  2. 建立名為「rate-limit-policy」的安全性政策:

      gcloud beta compute security-policies create rate-limit-policy \
          --global \
          --file-name=rate-limit-policy.yaml
    
  3. 在 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
    
  4. 建立名為 rate-limit-ep 的端點政策:

      gcloud beta network-services endpoint-policies import rate-limit-ep \
          --source=endpoints-policies.yaml \
          --location=global
    

為不同用戶端群組設定不同的伺服器端速率限制

在這個範例中,您會建立不同的伺服器端速率限制規則,為用戶端群組強制執行不同的速率限制門檻。

  1. 建立 Cloud Armor 安全性政策,類型為 CLOUD_ARMOR_INTERNAL_SERVICE,並包含多項速率限制規則,如下列檔案中定義的規則。在這些範例中,這個檔案稱為 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 項這類要求,這項政策就會對含有 HTTP 標頭 (名稱為 user,值為 demo) 的要求套用速率限制。如果 Cloud Service Mesh 在 60 秒內收到超過 10,000 個沒有這個 HTTP 標頭的要求,就會對這些要求進行速率限制。

  2. 使用下列指令建立名為 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 傳送至管理伺服器的用量報告,請參閱存取記錄

測試結果會顯示下列資訊:

  • 速率限制大約五分鐘後就會生效。
  • 經過初始暖機期後,您會看到 Nighthawk 用戶端輸出 benchmark.http_2xx 計數器顯示約 15 到 21 次的每秒查詢次數。也就是說,Cloud Armor 每分鐘允許約 1,000 個要求。

如要查看 Cloud Armor 安全性政策規則的效力,請參閱查看監控資訊主頁

停用頻率限制

您可以透過下列任一方法停用速率限制:

  • 您可以刪除使用速率限制規則設定的端點政策和安全性政策。
  • 更新端點政策,移除 securityPolicies 欄位,即可從端點政策卸離安全性政策。

以下各節說明如何使用各種方法停用速率限制。

刪除端點政策和安全性政策

首先,請使用下列 gcloud 指令刪除名為 rate-limit-ep 的端點政策。如果您使用本頁第一個或第二個範例中提供的名稱,端點政策會分別命名為 endpoints-policiesper-client-endpoints-policies

gcloud beta network-services endpoint-policies delete --location=global rate-limit-ep

然後使用下列 gcloud 指令刪除安全性政策,並將 per-client-security-policy 替換為安全性政策的名稱。如果您使用本頁面第一個或第二個範例中提供的名稱,則安全性政策的名稱會與端點政策的名稱相同。

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