内部マルチクラスタ Gateway をデプロイする

このドキュメントでは、内部マルチクラスタ Gateway をデプロイして、VPC ネットワーク内のトラフィックを 2 つの異なる GKE クラスタで実行されているアプリケーションにルーティングする実践的な例について説明します。

マルチクラスタ Gateway は、複数の GKE クラスタにデプロイされたサービスのトラフィックを管理する強力な方法を提供します。Google のグローバル ロード バランシング インフラストラクチャを使用すると、アプリケーションの単一のエントリ ポイントを作成できるため、管理が簡素化され、信頼性が向上します。

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

この例では、トラフィックを異なるクラスタに転送するようにパスベースのルーティングを設定する方法を示します。

始める前に

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

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

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

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

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

リージョン間で内部マルチクラスタ Gateway をデプロイする

複数のリージョンの GKE クラスタ間で内部レイヤ 7 ロード バランシングを提供するマルチクラスタ Gateway をデプロイできます。これらの Gateway は gke-l7-cross-regional-internal-managed-mc GatewayClass を使用します。この GatewayClass は、クロスリージョン内部アプリケーション ロードバランサをプロビジョニングします。これは Google Cloud によって管理され、VPC ネットワーク内のクライアントがアクセスできる内部 VIP を有効にします。これらの Gateway は、Gateway を使用して特定のリージョンのアドレスをリクエストするだけで、選択したリージョンのフロントエンドで公開できます。内部 VIP は単一の IP アドレスにすることも、複数のリージョンの IP アドレスにすることもできます。リージョンごとに 1 つの IP アドレスが Gateway で指定されます。トラフィックは、リクエストを処理できる最も近い正常なバックエンド GKE クラスタに転送されます。

前提条件

  1. プロジェクト ID を使用して gcloud 環境を構成し、プロジェクトとシェルを設定します。

    export PROJECT_ID="YOUR_PROJECT_ID"
    gcloud config set project ${PROJECT_ID}
    
  2. 複数のリージョンに GKE クラスタを作成します。

    この例では、us-west1gke-west-1us-east1gke-east-1 の 2 つのクラスタを使用します。Gateway API が有効(--gateway-api=standard)で、クラスタがフリートに登録されていることを確認します。

    gcloud container clusters create gke-west-1 \
        --location=us-west1-a \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --project=${PROJECT_ID} \
        --enable-fleet \
        --gateway-api=standard
    
    gcloud container clusters create gke-east-1 \
        --location=us-east1-c \
        --workload-pool=${PROJECT_ID}.svc.id.goog \
        --project=${PROJECT_ID} \
        --enable-fleet \
        --gateway-api=standard
    

    アクセスしやすいようにコンテキストの名前を変更します。

    gcloud container clusters get-credentials gke-west-1 \
      --location=us-west1-a \
      --project=${PROJECT_ID}
    
    gcloud container clusters get-credentials gke-east-1 \
      --location=us-east1-c \
      --project=${PROJECT_ID}
    kubectl config rename-context gke_${PROJECT_ID}_us-west1-a_gke-west-1 gke-west1
    kubectl config rename-context gke_${PROJECT_ID}_us-east1-c_gke-east-1 gke-east1
    
  3. マルチクラスタ Service(MCS)とマルチクラスタ Ingress(MCI / Gateway)を有効にします。

    gcloud container fleet multi-cluster-services enable --project=${PROJECT_ID}
    
    # Set the config membership to one of your clusters (e.g., gke-west-1)
    # This cluster will be the source of truth for multi-cluster Gateway and Route resources.
    gcloud container fleet ingress enable \
        --config-membership=projects/${PROJECT_ID}/locations/us-west1/memberships/gke-west-1 \
        --project=${PROJECT_ID}
    
  4. プロキシ専用サブネットを構成します。プロキシ専用サブネットは、GKE クラスタが配置される各リージョンと、ロードバランサが動作するリージョンに必要です。クロスリージョン内部アプリケーション ロードバランサでは、このサブネットの目的を GLOBAL_MANAGED_PROXY に設定する必要があります。

    # Proxy-only subnet for us-west1
    gcloud compute networks subnets create us-west1-proxy-only-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=us-west1 \
        --network=default \
        --range=10.129.0.0/23 # Choose an appropriate unused CIDR range
    
    # Proxy-only subnet for us-east1
    gcloud compute networks subnets create us-east1-proxy-only-subnet \
        --purpose=GLOBAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=us-east1 \
        --network=default \
        --range=10.130.0.0/23 # Choose an appropriate unused CIDR range
    

    デフォルトのネットワークを使用していない場合は、default を VPC ネットワークの名前に置き換えます。CIDR 範囲が一意であり、重複していないことを確認します。

  5. store などのデモ アプリケーションを両方のクラスタにデプロイします。gke-networking-recipesstore.yaml ファイルの例では、store Namespace と Deployment が作成されます。

    kubectl apply --context gke-west1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    kubectl apply --context gke-east1 -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/multi-cluster-gateway/store.yaml
    
  6. 各クラスタで Kubernetes Service リソースと ServiceExport リソースを作成して、各クラスタから Service をエクスポートします。これにより、フリート全体で Service を検出できるようになります。次の例では、各クラスタから汎用の store Service とリージョン固有の Service(store-west-1store-east-1)をエクスポートします。これらはすべて store Namespace 内にあります。

    gke-west1 に適用:

    cat << EOF | kubectl apply --context gke-west1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: store
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-west-1 # Specific to this cluster
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-west-1 # Exporting the region-specific service
      namespace: store
    EOF
    

    gke-east1 に適用:

    cat << EOF | kubectl apply --context gke-east1 -f -
    apiVersion: v1
    kind: Service
    metadata:
      name: store
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store
      namespace: store
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: store-east-1 # Specific to this cluster
      namespace: store
    spec:
      selector:
        app: store
      ports:
      - port: 8080
        targetPort: 8080
    ---
    kind: ServiceExport
    apiVersion: net.gke.io/v1
    metadata:
      name: store-east-1 # Exporting the region-specific service
      namespace: store
    EOF
    
  7. ServiceImport を確認します。ServiceImport リソースが各クラスタの store Namespace 内に作成されていることを確認します。作成には数分かかることがあります。bash kubectl get serviceimports --context gke-west1 -n store kubectl get serviceimports --context gke-east1 -n store storestore-west-1store-east-1(または、伝播に基づく関連エントリ)が一覧表示されます。

内部マルチリージョン Gateway を構成する

gke-l7-cross-regional-internal-managed-mc GatewayClass を参照する Gateway リソースを定義します。このマニフェストは、指定の構成クラスタ(gke-west-1 など)に適用します。

spec.addresses フィールドでは、特定リージョンのエフェメラル IP アドレスをリクエストすることも、事前に割り振られた静的 IP アドレスを使用することもできます。

  1. エフェメラル IP アドレスを使用するには、次の Gateway マニフェストを cross-regional-gateway.yaml として保存します。

    # cross-regional-gateway.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: internal-cross-region-gateway
      namespace: store # Namespace for the Gateway resource
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      # Addresses across regions. Address value is allowed to be empty or matching
      # the region name.
      - type: networking.gke.io/ephemeral-ipv4-address/us-west1
        value: "us-west1"
      - type: networking.gke.io/ephemeral-ipv4-address/us-east1
        value: "us-east1"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute # Only allow HTTPRoute to attach
    

    前の YAML ファイルの一部のフィールドの定義を以下に示します。

    • metadata.namespace: Gateway リソースが作成される Namespace(例: store)。
    • spec.gatewayClassName: GatewayClass の名前。必ず gke-l7-cross-regional-internal-managed-mc を指定します。
    • spec.listeners.allowedRoutes.kinds: 関連付けることができる Route オブジェクトの種類(HTTPRoute など)。
    • spec.addresses:
      • type: networking.gke.io/ephemeral-ipv4-address/REGION: エフェメラル IP アドレスをリクエストします。
      • value: アドレスのリージョンを指定します("us-west1""us-east1" など)。
  2. マニフェストを構成クラスタ(例: gke-west1)に適用します。

    kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
    

HTTPRoute を Gateway に接続する

トラフィック ルーティングを管理する HTTPRoute リソースを定義して、構成クラスタに適用します。

  1. 次の HTTPRoute マニフェストを store-route.yaml として保存します。

    # store-route.yaml
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: store-route
      namespace: store
      labels:
        gateway: cross-regional-internal
    spec:
      parentRefs:
      - name: internal-cross-region-gateway
        namespace: store # Namespace where the Gateway is deployed
      hostnames:
      - "store.example.internal" # Hostname clients will use
      rules:
      - matches: # Rule for traffic to /west
        - path:
            type: PathPrefix
            value: /west
        backendRefs:
        - group: net.gke.io # Indicates a multi-cluster ServiceImport
          kind: ServiceImport
          name: store-west-1 # Targets the ServiceImport for the west cluster
          port: 8080
      - matches: # Rule for traffic to /east
        - path:
            type: PathPrefix
            value: /east
        backendRefs:
        - group: net.gke.io
          kind: ServiceImport
          name: store-east-1 # Targets the ServiceImport for the east cluster
          port: 8080
      - backendRefs: # Default rule for other paths (e.g., /)
        - group: net.gke.io
          kind: ServiceImport
          name: store # Targets the generic 'store' ServiceImport (any region)
          port: 8080
    

    前の YAML ファイルの一部のフィールドの定義を以下に示します。

    • spec.parentRefs: このルートを store Namespace の internal-cross-region-gateway に関連付けます。
    • spec.hostnames: クライアントが Service にアクセスするために使用するホスト名を表します。
    • spec.rules: ルーティング ロジックを定義します。この例では、パスベースのルーティングを使用します。
      • /west トラフィックは store-west-1 ServiceImport に転送されます。
      • /east トラフィックは store-east-1 ServiceImport に転送されます。
      • / などの他のすべてのトラフィックは、汎用の store ServiceImport に送信されます。
    • backendRefs:
      • group: net.gke.iokind: ServiceImport はマルチクラスタ Service をターゲットにします。
  2. HTTPRoute マニフェストを構成クラスタに適用します。

    kubectl apply --context gke-west1 -f store-route.yaml
    

Gateway と Route のステータスを確認する

  1. Gateway のステータスを確認します。

    kubectl get gateway internal-cross-region-gateway -n store -o yaml --context gke-west1
    

    type: Programmed and status: "True" の条件を探します。. You should see IP addresses assigned in thestatus.addressesfield, corresponding to the regions you specified (e.g., one forus-west1and one forus-east1`).

  2. HTTPRoute のステータスを確認します。

    kubectl get httproute store-route -n store -o yaml --context gke-west1
    

    status.parents[].conditions で、type: Accepted(または ResolvedRefs)および status: "True" の条件を探します。

トラフィックを確認する

IP アドレスを Gateway に割り当てたら、VPC ネットワーク内のいずれかのリージョン(Gateway の IP アドレスに接続できるリージョン)にあるクライアント VM からトラフィックをテストできます。

  1. Gateway の IP アドレスを取得します。

    次のコマンドは、JSON 出力の解析を試みます。正確な構造に基づいて jsonpath を調整する必要がある場合があります。

    kubectl get gateway cross-region-gateway -n store --context gke-west1 -o=jsonpath="{.status.addresses[*].value}".
    

    このコマンドの出力には、VIP1_WESTVIP2_EAST などの VIP が含まれているはずです。

  2. VPC 内のクライアント VM からテスト リクエストを送信します。

    # Assuming VIP_WEST is an IP in us-west1 and VIP_EAST is an IP in us-east1
    # Traffic to /west should ideally be served by gke-west-1
    curl -H "host: store.example.internal" http://VIP_WEST/west
    curl -H "host: store.example.internal" http://VIP_EAST/west # Still targets store-west-1 due to path
    
    # Traffic to /east should ideally be served by gke-east-1
    curl -H "host: store.example.internal" http://VIP_WEST/east # Still targets store-east-1 due to path
    curl -H "host: store.example.internal" http://VIP_EAST/east
    
    # Traffic to / (default) could be served by either cluster
    curl -H "host: store.example.internal" http://VIP_WEST/
    curl -H "host: store.example.internal" http://VIP_EAST/
    

    レスポンスには、リクエストを処理したバックエンド Pod を示す store アプリケーションの詳細(cluster_namezone など)が含まれているはずです。

静的 IP アドレスを使用する

エフェメラル IP アドレスの代わりに、事前に割り振られた静的内部 IP アドレスを使用できます。

  1. 使用するリージョンに静的 IP アドレスを作成します。

    gcloud compute addresses create cross-region-gw-ip-west --region us-west1 --subnet default --project=${PROJECT_ID}
    gcloud compute addresses create cross-region-gw-ip-east --region us-east1 --subnet default --project=${PROJECT_ID}
    

    デフォルトのサブネットを使用していない場合は、default を、割り振る IP アドレスを持つサブネットの名前に置き換えます。これらのサブネットは、プロキシ専用サブネットではなく、通常のサブネットです。

  2. cross-regional-gateway.yaml ファイルの spec.addresses セクションを変更して、Gateway マニフェストを更新します。

    # cross-regional-gateway-static-ip.yaml
    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1
    metadata:
      name: internal-cross-region-gateway # Or a new name if deploying alongside
      namespace: store
    spec:
      gatewayClassName: gke-l7-cross-regional-internal-managed-mc
      addresses:
      - type: networking.gke.io/named-address-with-region # Use for named static IP
        value: "regions/us-west1/addresses/cross-region-gw-ip-west"
      - type: networking.gke.io/named-address-with-region
        value: "regions/us-east1/addresses/cross-region-gw-ip-east"
      listeners:
      - name: http
        protocol: HTTP
        port: 80
        allowedRoutes:
          kinds:
          - kind: HTTPRoute
    
  3. 更新された Gateway マニフェストを適用します。

    kubectl apply --context gke-west1 -f cross-regional-gateway.yaml
    

デフォルト以外のサブネットに関する特別な考慮事項

デフォルト以外のサブネットを使用する場合は、次の点に注意してください。

  • 同じ VPC ネットワーク: 静的 IP アドレス、プロキシ専用サブネット、GKE クラスタなど、ユーザーが作成したすべてのリソースが同じ VPC ネットワーク内に存在する必要があります。

  • アドレス サブネット: Gateway の静的 IP アドレスを作成すると、指定したリージョンの通常のサブネットから割り振られます。

  • クラスタ サブネットの命名: 各リージョンに、MCG 構成クラスタが存在するサブネットと同じ名前のサブネットが必要です。

    • たとえば、gke-west-1 構成クラスタが projects/YOUR_PROJECT/regions/us-west1/subnetworks/my-custom-subnet にある場合、アドレスをリクエストするリージョンにも my-custom-subnet サブネットが必要です。us-east1 リージョンと us-centra1 リージョンでアドレスをリクエストする場合は、これらのリージョンにも my-custom-subnet という名前のサブネットが存在する必要があります。

クリーンアップ

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

  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 のプロキシ専用サブネットが存在しない

内部 Gateway に次のイベントがある場合、そのリージョンにはプロキシ専用サブネットは存在しません。この問題を解決するには、プロキシ専用サブネットをデプロイします。

generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/us-west1/targetHttpProxies/gkegw-x5vt-default-internal-http-2jzr7e3xclhj'. A reserved and active subnetwork is required in the same region and VPC as the forwarding rule.

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

症状:

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

no healthy upstream

理由:

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

回避策:

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

次のステップ