容量ベースのロード バランシング用にマルチクラスタ Gateway をデプロイする

このドキュメントでは、異なるリージョンの 2 つの GKE クラスタにサンプル アプリケーションをデプロイする方法と、マルチクラスタ Gateway が Service 容量の上限を超えた場合にトラフィックをインテリジェントにルーティングする方法について説明します。

容量ベースのロード バランシングは、信頼性と復元力の高いアプリケーションの構築に役立つマルチクラスタ Gateway の機能です。サービスの容量を定義することで、サービスが過負荷になるのを防ぎ、ユーザーに一貫したエクスペリエンスを提供できます。1 つのクラスタの Service が容量に達すると、ロードバランサは使用可能な容量を持つ別のクラスタにトラフィックを自動的にリダイレクトします。トラフィック管理の詳細については、GKE トラフィック管理をご覧ください。

このチュートリアルでは、サンプル store アプリケーションを使用して、オンライン ショッピング サービスを複数のチームが所有して管理し、共有 GKE クラスタのフリート全体にデプロイしている実際のシナリオをシミュレートします。

始める前に

マルチクラスタ Gateway をデプロイする前に環境を用意する必要があります。続行する前に、マルチクラスタ Gateway 用に環境を準備するの手順を行ってください。

  1. GKE クラスタをデプロイします。

  2. クラスタをフリートに登録します(まだ登録されていない場合)。

  3. マルチクラスタ Service コントローラとマルチクラスタ Gateway コントローラを有効にします。

最後に、お使いの環境でコントローラを使用する前に、GKE Gateway コントローラの制限事項と既知の問題をご確認ください。

容量ベースのロード バランシングをデプロイする

このセクションの演習では、異なるリージョンの 2 つの GKE クラスタにアプリケーションをデプロイし、グローバル ロード バランシングと Service 容量のコンセプトを説明します。生成されたトラフィックを 1 秒あたりのリクエスト数(RPS)のさまざまなレベルで送信し、クラスタ間やリージョン間でのトラフィックのロード バランシングの方法を示します。

次の図は、デプロイするトポロジと、トラフィックが Service の容量を超えた場合にクラスタとリージョン間でトラフィックがオーバーフローする仕組みを示しています。

クラスタ間でオーバーフローするトラフィック

環境を準備する

  1. マルチクラスタ Gateway の環境を準備するに沿って環境を準備します。

  2. GatewayClass リソースが構成クラスタにインストールされていることを確認します。

    kubectl get gatewayclasses --context=gke-west-1
    

    出力は次のようになります。

    NAME                                  CONTROLLER                  ACCEPTED   AGE
    gke-l7-global-external-managed        networking.gke.io/gateway   True       16h
    gke-l7-global-external-managed-mc     networking.gke.io/gateway   True       14h
    gke-l7-gxlb                           networking.gke.io/gateway   True       16h
    gke-l7-gxlb-mc                        networking.gke.io/gateway   True       14h
    gke-l7-regional-external-managed      networking.gke.io/gateway   True       16h
    gke-l7-regional-external-managed-mc   networking.gke.io/gateway   True       14h
    gke-l7-rilb                           networking.gke.io/gateway   True       16h
    gke-l7-rilb-mc                        networking.gke.io/gateway   True       14h
    

アプリケーションをデプロイする

両方のクラスタにサンプルのウェブ アプリケーション サーバーをデプロイします。

kubectl apply --context gke-west-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml
kubectl apply --context gke-east-1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/master/gateway/docs/store-traffic-deploy.yaml

出力は次のようになります。

namespace/store created
deployment.apps/store created

Service、Gateway、HTTPRoute をデプロイする

  1. 次の Service マニフェストを gke-west-1 クラスタと gke-east-1 クラスタの両方に適用します。

    cat << EOF | kubectl apply --context gke-west-1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: traffic-test
      annotations:
        networking.gke.io/max-rate-per-endpoint: "10"
    spec:
      ports:
      - port: 8080
        targetPort: 8080
        name: http
      selector:
        app: store
      type: ClusterIP
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: traffic-test
    EOF
    
    cat << EOF | kubectl apply --context gke-east-1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: traffic-test
      annotations:
        networking.gke.io/max-rate-per-endpoint: "10"
    spec:
      ports:
      - port: 8080
        targetPort: 8080
        name: http
      selector:
        app: store
      type: ClusterIP
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: traffic-test
    EOF
    

    Service は、1 秒あたり 10 リクエストに設定された max-rate-per-endpoint でアノテーションされます。クラスタあたり 2 つのレプリカがある場合、各 Service にはクラスタごとに 20 RPS の容量があります。

    Service の Service 容量レベルを選択する方法の詳細については、Service の容量を決定するをご覧ください。

  2. 次の Gateway マニフェストを構成クラスタに適用します(この例では gke-west-1)。

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store
      namespace: traffic-test
    spec:
      gatewayClassName: gke-l7-global-external-managed-mc
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    EOF
    

    このマニフェストでは、一般公開された IP アドレスを持つ外部アプリケーション ロードバランサをデプロイする、グローバルな外部マルチクラスタ Gateway について記述します。

  3. 次の HTTPRoute マニフェストを構成クラスタに適用します(この例では gke-west-1)。

    cat << EOF | kubectl apply --context gke-west-1 -f -
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store
      namespace: traffic-test
      labels:
        gateway: store
    spec:
      parentRefs:
      - kind: Gateway
        namespace: traffic-test
        name: store
      rules:
      - backendRefs:
        - name: store
          group: net.gke.io
          kind: ServiceImport
          port: 8080
    EOF
    

    このマニフェストでは、すべてのトラフィックをストア ServiceImport に転送するルーティング ルールで Gateway を構成する HTTPRoute について記述します。store ServiceImport は、両方のクラスタで store Service Pod をグループ化し、ロードバランサでそれらの Pod を 1 つの Service としてアドレス指定できます。

    数分後に Gateway のイベントをチェックして、デプロイが完了したかどうかを確認できます。

    kubectl describe gateway store -n traffic-test --context gke-west-1
    

    出力は次のようになります。

    ...
    Status:
      Addresses:
        Type:   IPAddress
        Value:  34.102.159.147
      Conditions:
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:               The OSS Gateway API has deprecated this condition, do not depend on it.
        Observed Generation:   1
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:
        Observed Generation:   1
        Reason:                Accepted
        Status:                True
        Type:                  Accepted
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:
        Observed Generation:   1
        Reason:                Programmed
        Status:                True
        Type:                  Programmed
        Last Transition Time:  2023-10-12T21:40:59Z
        Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
        Observed Generation:   1
        Reason:                Ready
        Status:                True
        Type:                  Ready
      Listeners:
        Attached Routes:  1
        Conditions:
          Last Transition Time:  2023-10-12T21:40:59Z
          Message:
          Observed Generation:   1
          Reason:                Programmed
          Status:                True
          Type:                  Programmed
          Last Transition Time:  2023-10-12T21:40:59Z
          Message:               The OSS Gateway API has altered the "Ready" condition semantics and reservedit for future use.  GKE Gateway will stop emitting it in a future update, use "Programmed" instead.
          Observed Generation:   1
          Reason:                Ready
          Status:                True
          Type:                  Ready
        Name:                    http
        Supported Kinds:
          Group:  gateway.networking.k8s.io
          Kind:   HTTPRoute
    Events:
      Type    Reason  Age                  From                   Message
      ----    ------  ----                 ----                   -------
      Normal  ADD     12m                  mc-gateway-controller  traffic-test/store
      Normal  SYNC    6m43s                mc-gateway-controller  traffic-test/store
      Normal  UPDATE  5m40s (x4 over 12m)  mc-gateway-controller  traffic-test/store
      Normal  SYNC    118s (x6 over 10m)   mc-gateway-controller  SYNC on traffic-test/store was a success
    

    この出力は、Gateway が正常にデプロイされたことを示しています。Gateway をデプロイしてからトラフィックが通過し始めるまでに数分かかることがあります。次のステップで使用するため、この出力の IP アドレスをメモしておきます。

トラフィックを確認する

curl コマンドを使用して、Gateway の IP アドレスをテストし、トラフィックがアプリケーションに渡されることを確認します。

curl GATEWAY_IP_ADDRESS

出力は次のようになります。

{
  "cluster_name": "gke-west-1",
  "host_header": "34.117.182.69",
  "pod_name": "store-54785664b5-mxstv",
  "pod_name_emoji": "👳🏿",
  "project_id": "project",
  "timestamp": "2021-11-01T14:06:38",
  "zone": "us-west1-a"
}

この出力には、リクエストが提供されたリージョンを示す Pod メタデータが表示されます。

負荷テストを使用してトラフィックを確認する

ロードバランサが機能していることを確認するには、gke-west-1 クラスタにトラフィック生成ツールをデプロイします。トラフィック生成ツールは、さまざまな負荷レベルでトラフィックを生成し、ロードバランサの容量とオーバーフロー機能を実証します。次の手順では、3 つのレベルの負荷を示します。

  • 10 RPS。これは gke-west-1 内のストア Service の容量を下回っています。
  • 30 RPS。これは gke-west-1 ストア Service の容量を超えているため、トラフィックが gke-east-1 にオーバーフローします。
  • 60 RPS。これは、両方のクラスタで Service の容量を超えています。

ダッシュボードを構成

  1. Gateway の基盤となっている URL マップの名前を取得します。

    kubectl get gateway store -n traffic-test --context=gke-west-1 -o=jsonpath="{.metadata.annotations.networking\.gke\.io/url-maps}"
    

    出力は次のようになります。

    /projects/PROJECT_NUMBER/global/urlMaps/gkemcg1-traffic-test-store-armvfyupay1t
    
  2. Google Cloud コンソールで、Metrics Explorer のページに移動します。

    Metrics Explorer に移動

  3. [指標を選択] で、[CODE: MQL] をクリックします。

  4. 次のクエリを入力して、2 つのクラスタ全体にわたるストア Service のトラフィック指標を確認します。

    fetch https_lb_rule
    | metric 'loadbalancing.googleapis.com/https/backend_request_count'
    | filter (resource.url_map_name == 'GATEWAY_URL_MAP')
    | align rate(1m)
    | every 1m
    | group_by [resource.backend_scope],
        [value_backend_request_count_aggregate:
            aggregate(value.backend_request_count)]
    

    GATEWAY_URL_MAP は、前の手順での URL マップ名に置き換えます。

  5. [クエリを実行] をクリックします。次のセクションで負荷生成ツールをデプロイしてから、指標がグラフに表示されるまで、少なくとも 5 分は待ちます。

10 RPS でテストする

  1. Pod を gke-west-1 クラスタにデプロイします。

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 10'
    

    GATEWAY_IP_ADDRESS は、前の手順で取得した Gateway IP アドレスに置き換えます。

    出力は次のようになります。これは、トラフィック生成ツールがトラフィックを送信していることを示しています。

    If you don't see a command prompt, try pressing enter.
    

    負荷生成ツールは Gateway に継続的に 10 RPS を送信します。トラフィックが Google Cloud リージョン内から送信されていても、ロードバランサは米国西海岸から送信されるクライアント トラフィックとして扱います。現実的なクライアント多様性をシミュレートするために、負荷生成ツールは各 HTTP リクエストを新しい TCP 接続として送信します。つまり、トラフィックはバックエンド Pod 間でより均等に分散されます。

    生成ツールがダッシュボードのトラフィックを生成するまでに最大 5 分かかります。

  2. Metrics Explorer ダッシュボードを表示します。各クラスタにロードバランシングされるトラフィックの量を示す 2 つの行が表示されます。

    クラスタにロードバランシングされたトラフィックを示すグラフ

    us-west1-a が約 10 RPS のトラフィックを受信しているのに対し、us-east1-b はトラフィックを受信していないことがわかります。トラフィック生成ツールは us-west1 で実行されているため、すべてのトラフィックは gke-west-1 クラスタ内の Service に送信されます。

  3. Ctrl+C を使用して負荷生成ツールを停止してから、Pod を削除します。

    kubectl delete pod loadgen --context gke-west-1
    

30 RPS でテストする

  1. 負荷生成ツールを再度デプロイしますが、送信は 30 RPS となるよう構成します。

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 30'
    

    生成ツールがダッシュボードのトラフィックを生成するまでに最大 5 分かかります。

  2. Cloud Ops ダッシュボードを表示します。

    gke-east-1 に対してオーバーフローするトラフィックを示すグラフ

    約 20 RPS が us-west1-a に送信され、10 RPS が us-east1-b に送信されていることがわかります。これは、gke-west-1 の Service が完全に使用されており、10 RPS のトラフィックが gke-east-1 の Service へオーバーフローしていることを示しています。

  3. Ctrl+C を使用して負荷生成ツールを停止してから、Pod を削除します。

    kubectl delete pod loadgen --context gke-west-1
    

60 RPS でテストする

  1. 60 RPS を送信するように構成された負荷生成ツールをデプロイします。

    kubectl run --context gke-west-1 -i --tty --rm loadgen  \
        --image=cyrilbkr/httperf  \
        --restart=Never  \
        -- /bin/sh -c 'httperf  \
        --server=GATEWAY_IP_ADDRESS  \
        --hog --uri="/zone" --port 80  --wsess=100000,1,1 --rate 60'
    
  2. 5 分待ってから、Cloud Ops ダッシュボードを表示します。両方のクラスタが約 30 RPS を受信していることがわかります。すべての Service はグローバルで過剰に使用されているため、トラフィックのスピルオーバーはなく、各 Service は可能な限りすべてのトラフィックを吸収します。

    Service の過剰使用を示すグラフ

  3. Ctrl+C を使用して負荷生成ツールを停止してから、Pod を削除します。

    kubectl delete pod loadgen --context gke-west-1
    

クリーンアップ

このドキュメントの演習を完了したら、アカウントで不要な請求が発生しないように、以下の手順でリソースを削除します。

  1. クラスタを削除します

  2. 他の目的で登録する必要がない場合は、フリートからクラスタの登録を解除します。

  3. multiclusterservicediscovery 機能を無効にします。

    gcloud container fleet multi-cluster-services disable
    
  4. マルチクラスタ Ingress を無効にします。

    gcloud container fleet ingress disable
    
  5. API を無効にします。

    gcloud services disable \
        multiclusterservicediscovery.googleapis.com \
        multiclusteringress.googleapis.com \
        trafficdirector.googleapis.com \
        --project=PROJECT_ID
    

トラブルシューティング

正常なアップストリームがない

症状:

Gateway を作成してもバックエンド サービスにアクセスできない場合(503 レスポンス コード)、次の問題が発生している可能性があります。

no healthy upstream

理由:

このエラー メッセージは、ヘルスチェック プローバーが正常なバックエンド サービスを見つけられないことを示します。バックエンド サービスは正常である可能性がありますが、ヘルスチェックのカスタマイズが必要になる場合もあります。

回避策:

この問題を解決するには、HealthCheckPolicy を使用して、アプリケーションの要件(/health など)に基づいてヘルスチェックをカスタマイズします。

次のステップ