Gateway のデプロイ


このページでは、上り(内向き)トラフィックを単一の Google Kubernetes Engine(GKE)クラスタにロードバランスするために Kubernetes Gateway リソースをデプロイする方法について説明します。

Gateway をデプロイして複数のクラスタ(またはフリート)間で上り(内向き)トラフィックをロードバランスする方法については、マルチクラスタ Gateway のデプロイをご覧ください。

始める前に

作業を始める前に、次のことを確認してください。

  • Google Kubernetes Engine API を有効にします。
  • Google Kubernetes Engine API の有効化
  • このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化します。すでに gcloud CLI をインストールしている場合は、gcloud components update を実行して最新のバージョンを取得します。

GKE Gateway Controller の要件

  • Standard の場合は GKE バージョン 1.24 以降。
  • Autopilot の場合は GKE バージョン 1.26 以降。
  • Google Cloud CLI バージョン 407.0.0 以降。
  • Gateway API は、VPC ネイティブ クラスタでのみサポートされます。
  • 内部 GatewayClass を使用している場合は、プロキシ専用サブネットを有効にする必要があります。
  • クラスタで HttpLoadBalancing アドオンが有効になっている必要があります。
  • Istio を使用している場合は、Istio を次のいずれかのバージョンにアップグレードする必要があります。
    • 1.15.2 以降
    • 1.14.5 以降
    • 1.13.9 以降
  • 共有 VPC を使用している場合は、ホスト プロジェクトで、サービス プロジェクトの GKE サービス アカウントに Compute Network User ロールを割り当てる必要があります。

制限事項

  • GKE GatewayClasses がサポートする機能は、使用するロードバランサによって異なります。GatewayClass でサポートされている機能の詳細については、GatewayClass の機能をご覧ください。

  • FrontendConfig または BackendConfig を使用して Gateway を構成することはできません。ポリシーを使用する必要があります。

  • Ingress とは異なり、GKE Gateway はヘルスチェックのパラメータを推定しません。Service が GET / へのリクエストに対して 200 を返さない場合、または他の調整された Pod の readiness チェックがある場合は、サービスの HealthCheckPolicy を構成する必要があります。

  • GKE が Gateway 用に作成したロードバランサ リソースは、Google Cloud コンソールで確認できますが、これらのリソースは接続先の Gateway や GKE クラスタを参照しません。

  • Google Cloud コンソールで Gateway、HTTPRoute、Policy のリソースを確認することはできません。Gateway リソースを検出して管理する場合は、Kubernetes API を使用します。

* Gateway を使用して Google マネージド SSL 証明書を自動的に生成することはできませんが、Google マネージド SSL 証明書を手動で作成して参照することはできます。詳細については、Gateway を保護するをご覧ください。
  • Route タイプとしてサポートされているのは HTTPRoute だけです。TCPRoutes、UDPRoutes、TLSRoutes はサポートされていません。GKE Gateway Controller がサポートするフィールドの一覧については、GatewayClass の機能をご覧ください。

  • Gateway を含むカスタム リクエストとレスポンス ヘッダー、または Gateway を使用したパス リダイレクトと URL の書き換えは、GKE バージョン 1.27 以降でのみ使用できます。

  • Gateway を含むカスタム リクエストとレスポンス ヘッダー、および Gateway を使用したパス リダイレクトと URL の書き換えの場合、GatewayClass gke-l7-gxlb はサポートされません。
  • 次の Google Cloud ヘッダー変数はサポートされていません。

    • cdn_cache_id(Cloud CDN は GKE Gateway でサポートされていません)
    • cdn_cache_status(Cloud CDN は GKE Gateway でサポートされていません)
    • origin_request_header(CORS は GKE Gateway でサポートされていません)
  • GKE Gateway は Cloud CDN のロード バランシング機能をサポートしていません。

  • 相互 TLS カスタム ヘッダーはサポートされていません(GKE Gateway で mTLS はサポートされていません)。

  • Google Cloud の従来のアプリケーション ロードバランサの制限は GKE Gateway に適用されます。さらに、次の制限も適用されます。

    • バックエンド サービスでカスタムの Host レスポンス ヘッダーを構成することはできません。
  • パス リダイレクトと URL の書き換えは相互に排他的です。同じルールで両方のフィルタを同時に使用することはできません。

  • Cloud Load Balancing でトラフィックを別のポートにリダイレクトすることはできません。GKE Gateway Controller がサポートするフィールドの一覧については、GatewayClass の機能をご覧ください。

  • GKE Gateway は、ワイルドカード、正規表現、動的 URL をサポートしていません。

  • リージョン外部ゲートウェイ クラスを使用して Gateway を指定すると、コントローラは外部アドレスではなく内部 IP アドレスをプロビジョニングします。リージョン外部アプリケーション ロードバランサで名前付きアドレスを使用する方法については、リージョン外部 Gateway をデプロイするをご覧ください。

  • Gateway は、ネットワーク エンドポイント グループのプロビジョニングにスタンドアロン NEG を利用します。Gateway コントローラがロードバランサの構成を適切に調整できるようにするため、Gateway の一部である Service の cloud.google.com/neg アノテーションを変更することはできません。

  • GKE Gateway は、GKE Ingress でも参照される Service の参照をサポートしていません。

  • IP アドレスをプロビジョニングするように Gateway が構成されている場合、Gateway.spec.gatewayClass の変更はサポートされません。Gateway コントローラがロードバランサを適切に調整できるようにするため、既存の Gateway を削除し、更新された gatewayClass 値を含むマニフェストを再度デプロイします。

  • networking.gke.io/app-protocols アノテーションはサポートされていません。同じ結果を得るには、代わりに appProtocol フィールドを使用してください。

クラスタで Gateway API を有効にする

GKE で Gateway リソースを使用する前に、クラスタで Gateway API を有効にしておく必要があります。

Gateway API を有効にして新しいクラスタを作成する

GKE バージョン 1.26 以降では、GKE は Autopilot クラスタで Gateway API をサポートします。GKE 1.26 以降で新しい Autopilot クラスタを作成すると、Gateway API はデフォルトで有効になります。GKE バージョン 1.25 以前の既存のクラスタでは、Gateway API はデフォルトで無効になっています。

Autopilot

Gateway API を有効にする新しい GKE Autopilot クラスタを作成します。

  gcloud container clusters create-auto CLUSTER_NAME \
      --location=CLUSTER_LOCATION \
      --release-channel=RELEASE_CHANNEL \
      --cluster-version=VERSION

次のように置き換えます。

  • CLUSTER_NAME: クラスタの名前。
  • CLUSTER_LOCATION: 新しいクラスタの Compute Engine のリージョンまたはゾーン
  • RELEASE_CHANNEL: リリース チャンネルの名前。
  • VERSION: GKE のバージョン。1.26 以降にする必要があります。また、--release-channel フラグを使用してリリース チャンネルを選択することもできます。リリース チャンネルには、デフォルトのバージョン 1.26 以降が必要です。

Standard

GKE Standard では、Gateway API は --gateway-api フラグで制御されます。有効にする場合は値に standard を使用し、無効にする場合は値に disabled を使用します。

Gateway API が有効になっている新しい VPC ネイティブの GKE クラスタを作成します。

  gcloud container clusters create CLUSTER_NAME \
    --gateway-api=standard \
    --cluster-version=VERSION \
    --location=CLUSTER_LOCATION

次のように置き換えます。

  • RELEASE_CHANNEL: リリース チャンネルの名前。
  • CLUSTER_NAME: クラスタの名前。
  • VERSION: GKE のバージョン。1.24 以降にする必要があります。また、--release-channel フラグを使用してリリース チャンネルを選択することもできます。リリース チャンネルを使用するには、デフォルトのバージョン 1.24 以降が必要です。
  • CLUSTER_LOCATION: 新しいクラスタの Compute Engine のリージョンまたはゾーン

--gateway-api=standard フラグを指定すると、GKE は、クラスタと v1beta1 CRD をインストールします。

既存のクラスタで Gateway API を有効にする

Autopilot クラスタのバージョンが 1.26 以降で、Standard クラスタのバージョンが 1.24 以降であることを確認します。

既存の GKE クラスタ(Autopilot または Standard)で Gateway API を有効にするには、次のコマンドを使用します。

gcloud container clusters update CLUSTER_NAME \
    --location=CLUSTER_LOCATION\
    --gateway-api=standard

次のように置き換えます。

--gateway-api=standard フラグを指定すると、GKE は、クラスタと v1beta1 CRD をインストールします。

クラスタを確認する

クラスタを作成またはアップグレードすると、GKE Gateway Controller は GatewayClass を自動的にインストールします。コントローラが CRD を認識してから GatewayClass をインストールするまでに数分かかることがあります。

  1. GKE コントロール プレーンで Gateway API が有効になっていることを確認します。

    gcloud container clusters describe CLUSTER_NAME \
      --location=CLUSTER_LOCATION \
      --format json
    

    出力は次のようになります。この出力が空の場合は、cluster update コマンドを再実行します。

    "networkConfig": {
      ...
      "gatewayApiConfig": {
        "channel": "CHANNEL_STANDARD"
      },
      ...
    },
    
  2. GatewayClasses がクラスタにインストールされていることを確認します。

    kubectl get gatewayclass
    

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

```none {:.devsite-disable-click-to-copy}
NAME                             CONTROLLER                  ACCEPTED   AGE
gke-l7-global-external-managed   networking.gke.io/gateway   True       16h
gke-l7-regional-external-managed networking.gke.io/gateway   True       16h
gke-l7-gxlb                      networking.gke.io/gateway   True       16h
gke-l7-rilb                      networking.gke.io/gateway   True       16h
```

各 GatewayClass の機能については、GatewayClass の機能をご覧ください。

注: 単一クラスタの GatewayClass のみが自動的にインストールされます。内部および外部マルチクラスタ ロード バランシング用のマルチクラスタ GatewayClass をインストールして使用するには、マルチクラスタ Gateway の有効化をご覧ください。

内部 Gateway をデプロイする

内部 Gateway は、VPC または VPC に接続されているネットワーク内からのみ到達可能なアプリケーションを公開します。

リージョン内部 Gateway をデプロイする

次の例は、特定の地理的リージョン内のサービス間で効率的かつ安全な通信を可能にするリージョン内部 Gateway をデプロイする方法を示しています。

プロキシ専用サブネットを構成する

内部アプリケーション ロードバランサを使用する Gateway を作成する前に、プロキシ専用サブネットを構成する必要があります。内部アプリケーション ロードバランサを使用する VPC の各リージョンには、プロキシ専用サブネットが必要です。このサブネットは、ロードバランサ プロキシに内部 IP アドレスを提供します。

  1. プロキシ専用サブネットを作成します。

    gcloud compute networks subnets create SUBNET_NAME \
        --purpose=REGIONAL_MANAGED_PROXY \
        --role=ACTIVE \
        --region=COMPUTE_REGION \
        --network=VPC_NETWORK_NAME \
        --range=CIDR_RANGE
    

    次のように置き換えます。

    • SUBNET_NAME: プロキシ専用サブネットの名前。
    • COMPUTE_REGION: プロキシ専用サブネットのリージョン。
    • VPC_NETWORK_NAME: サブネットを含む VPC ネットワークの名前。
    • CIDR_RANGE: サブネットのプライマリ IP アドレス範囲。サブネット マスクの長さは /26 以下にして、リージョン内のプロキシで 64 個以上の IP アドレスを使用できるようにします。推奨のサブネット マスクは /23 です。
  2. プロキシ専用サブネットを確認します。

    gcloud compute networks subnets describe SUBNET_NAME \
        --region=COMPUTE_REGION
    

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

    ...
    gatewayAddress: 10.1.1.1
    ipCidrRange: 10.1.1.0/24
    kind: compute#subnetwork
    name: proxy-subnet
    network: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/global/networks/default
    privateIpGoogleAccess: false
    privateIpv6GoogleAccess: DISABLE_GOOGLE_ACCESS
    purpose: REGIONAL_MANAGED_PROXY
    region: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/regions/REGION
    role: ACTIVE
    selfLink: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/regions/REGION/subnetworks/proxy-subnet
    state: READY
    

Gateway を作成する

Gateway リソースは、Kubernetes のトラフィックをルーティングするデータプレーンを表します。Gateway は、派生元の GatewayClass に応じて、さまざまなロード バランシングとルーティングを表すことができます。Gateway リソースの詳細については、Gateway リソースの説明または API 仕様をご覧ください。

このケースでは、GKE クラスタの管理者は、さまざまなチームがアプリケーションを内部で公開するための Gateway を作成したいと考えています。管理者が Gateway をデプロイして、アプリケーション チームが Route を個別にデプロイし、Gateway に接続します。

  1. 次の Gateway マニフェストを gateway.yaml という名前のファイルに保存します。

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: internal-http
    spec:
      gatewayClassName: gke-l7-rilb
      listeners:
      - name: http
        protocol: HTTP
        port: 80
    

    このマニフェストには次のフィールドがあります。

    • gatewayClassName: gke-l7-rilb: この Gateway の派生元となる GatewayClass を指定します。gke-l7-rilb は、内部アプリケーション ロードバランサに対応しています。
    • port: 80: HTTP トラフィックをリッスンするためにポート 80 のみを公開することを指定します。
  2. クラスタに Gateway をデプロイします。

    kubectl apply -f gateway.yaml
    
  3. Gateway が正しくデプロイされたことを確認します。すべてのリソースがデプロイされるまで数分かかる場合があります。

    kubectl describe gateways.gateway.networking.k8s.io internal-http
    

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

    Name:         internal-http
    Namespace:    default
    Spec:
      Gateway Class Name:  gke-l7-rilb
      Listeners:
        Allowed Routes:
          Kinds:
            Group:  gateway.networking.k8s.io
            Kind:   HTTPRoute
          Namespaces:
            From:  Same
        Name:      http
        Port:      80
        Protocol:  HTTP
    Status:
      Addresses:
        Type:   IPAddress
        Value:  192.168.1.14
      Conditions:
        Last Transition Time:  1970-01-01T00:00:00Z
        Message:               Waiting for controller
        Reason:                NotReconciled
        Status:                False
        Type:                  Scheduled
    Events:
      Type    Reason  Age                From                       Message
      ----    ------  ----               ----                       -------
      Normal  ADD     92s                networking.gke.io/gateway  test/internal-http
      Normal  UPDATE  45s (x3 over 91s)  networking.gke.io/gateway  test/internal-http
      Normal  SYNC    45s                networking.gke.io/gateway  SYNC on test/internal-http was a success
    

    この時点で、ロードバランサと IP アドレスをプロビジョニングしているクラスタに Gateway がデプロイされます。ただし、Gateway には Route がないため、バックエンドにトラフィックを送信する方法がわかりません。Route を使用しないと、すべてのトラフィックがデフォルトのバックエンドに移動し、HTTP 404 を返します。次に、アプリケーションと Route をデプロイします。これにより、Gateway にアプリケーション バックエンドの取得方法が指示されます。

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

アプリケーション チームは、Gateway のデプロイとは別にアプリケーションと Route をデプロイできます。アプリケーション チームで Gateway を所有し、アプリケーション専用のリソースとしてデプロイすることもできます。Gateway と Route のさまざまな所有権モデルについては、ルート バインディングをご覧ください。しかし、この例では、ストアチームがアプリケーションと付属の HTTPRoute をデプロイし、前のセクションで作成した internal-http Gateway 経由でアプリを公開します。

HTTPRoute リソースには、トラフィック照合用の構成可能なフィールドが多数あります。HTTPRoute のフィールドの説明については、API の仕様をご覧ください。

  1. ストア アプリケーション(store-v1、store-v2、store-german のデプロイ)をクラスタにデプロイします。

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/store.yaml
    

    これにより、3 つの Deployment と、store-v1、store-v2、store-german という名前の 3 つの Service が作成されます。

  2. アプリケーションのデプロイが成功したことを確認します。

    kubectl get pod
    

    アプリケーションが稼働した後の出力は次のようになります。

    NAME                        READY   STATUS    RESTARTS   AGE
    store-german-66dcb75977-5gr2n   1/1     Running   0          38s
    store-v1-65b47557df-jkjbm       1/1     Running   0          14m
    store-v2-6856f59f7f-sq889       1/1     Running   0          14m
    
  3. Service がデプロイされていることを確認します。

    kubectl get service
    

    出力には、各ストア Deployment の Service が表示されます。

    NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    store-german   ClusterIP   10.48.3.183   <none>        8080/TCP   4s
    store-v1       ClusterIP   10.48.2.224   <none>        8080/TCP   5s
    store-v2       ClusterIP   10.48.4.48    <none>        8080/TCP   5s
    

HTTPRoute をデプロイする

Route リソースは、Gateway から Kubernetes バックエンドにトラフィックをマッピングするためのプロトコル固有のルールを定義します。HTTPRoute リソースは、HTTP および HTTPS トラフィックの照合とフィルタリングを行います。これは、すべての gke-l7 GatewayClasss でサポートされています。

このセクションでは、HTTPRoute をデプロイし、トア アプリケーションに到達するために必要なルーティング ルールを使用して Gateway を制御します。

  1. 次の HTTPRoute マニフェストを store-route.yaml という名前のファイルに保存します。

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store
    spec:
      parentRefs:
      - kind: Gateway
        name: internal-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
      - matches:
        - headers:
          - name: env
            value: canary
        backendRefs:
        - name: store-v2
          port: 8080
      - matches:
        - path:
            value: /de
        backendRefs:
        - name: store-german
          port: 8080
    
  2. クラスタに HTTProute をデプロイします。

    kubectl apply -f store-route.yaml
    

    store HTTPRoute は parentRefs プロパティを使用して internal-http Gateway にバインドされます。次の図のように、これらのルーティング ルールは基盤となるロードバランサで構成されます。

    ストアの HTTPRoute によって構成されたルーティング ルール

    これらのルーティング ルールは HTTP トラフィックを次のように処理します。

    • store.example.com/de へのトラフィックは、Service store-german に送信されます。
    • HTTP ヘッダー "env: canary" を含む store.example.com へのトラフィックは、Service store-v2 に送信されます。
    • store.example.com への残りのトラフィックは、Service store-v1 に送信されます。
  3. HTTPRoute がデプロイされていることを確認します。

    kubectl describe httproute store
    

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

    Name:         store
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    API Version:  gateway.networking.k8s.io/v1beta1
    Kind:         HTTPRoute
    <...>
    Spec:
      Hostnames:
        store.example.com
      Parent Refs:
        Group:  gateway.networking.k8s.io
        Kind:   Gateway
        Name:   internal-http
      Rules:
        Backend Refs:
          Group:
          Kind:    Service
          Name:    store-v1
          Port:    8080
          Weight:  1
        Matches:
          Path:
            Type:   PathPrefix
            Value:  /
        Backend Refs:
          Group:
          Kind:    Service
          Name:    store-v2
          Port:    8080
          Weight:  1
        Matches:
          Headers:
            Name:   env
            Type:   Exact
            Value:  canary
          Path:
            Type:   PathPrefix
            Value:  /
        Backend Refs:
          Group:
          Kind:    Service
          Name:    store-german
          Port:    8080
          Weight:  1
        Matches:
          Path:
            Type:   PathPrefix
            Value:  /de
    Status:
      Parents:
        Conditions:
          Last Transition Time:  2022-11-01T04:18:52Z
          Message:
          Reason:                Accepted
          Status:                True
          Type:                  Accepted
          Last Transition Time:  2022-11-01T04:18:52Z
          Message:
          Reason:                ReconciliationSucceeded
          Status:                True
          Type:                  Reconciled
        Controller Name:         networking.gke.io/gateway
        Parent Ref:
          Group:  gateway.networking.k8s.io
          Kind:   Gateway
          Name:   internal-http
    Events:
      Type    Reason  Age                From                   Message
      ----    ------  ----               ----                   -------
      Normal  ADD     24m                sc-gateway-controller  default/store
      Normal  SYNC    16m (x4 over 23m)  sc-gateway-controller  Bind of HTTPRoute "default/store" to ParentRef {Group:       gateway.networking.k8s.io",
      <...>
    
  4. HTTPRoute が Gateway にバインドされていることを確認します。

    kubectl describe gateway
    

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

    Name:         internal-http
    Namespace:    default
    Labels:       <none>
    <...>
    Status:
      Addresses:
        Type:   IPAddress
        Value:  10.128.15.203
      Conditions:
        Last Transition Time:  2022-11-01T03:47:01Z
        Message:
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
        Last Transition Time:  2022-11-01T03:47:01Z
        Message:
        Reason:                Ready
        Status:                True
        Type:                  Ready
      Listeners:
        Attached Routes:  1
        Conditions:
          Last Transition Time:  2022-11-01T03:47:01Z
          Message:
          Reason:                Ready
          Status:                True
          Type:                  Ready
        Name:                    http
        Supported Kinds:
          Group:  gateway.networking.k8s.io
          Kind:   HTTPRoute
          <...>
    

アプリケーションにトラフィックを送信する

クラスタに Gateway、Route、アプリケーションがデプロイされたので、アプリケーションにトラフィックを送信してみましょう。

  1. アプリケーションにトラフィックを送信できるように、Gateway から IP アドレスを取得します。

    kubectl get gateways.gateway.networking.k8s.io internal-http -o=jsonpath="{.status.addresses[0].value}"
    

    出力は IP アドレスです。

  2. クラスタに接続している仮想マシン(VM)インスタンスのシェルから、この IP アドレスにトラフィックを送信します。この目的で使用する VM を作成することもできます。Gateway に内部 IP アドレスが割り振られ、VPC ネットワーク内からのみアクセスされるため、この操作が必要になります。internal-http はリージョン ロードバランサです。クライアント シェルは GKE クラスタと同じリージョン内に存在する必要があります。

    example.com ホスト名の所有者ではないため、ホストヘッダーを手動で設定してトラフィック ルーティングを監視できるようにします。最初に store.example.com にリクエストを送信してみましょう。

    curl -H "host: store.example.com" VIP
    

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

    デモアプリの出力には、アプリが実行されている場所に関する情報が含まれます。

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.gateway-demo-243723.internal",
      "pod_name": "store-v1-84b47c7f58-pmgmk",
      "pod_name_emoji": "💇🏼‍♀️",
      "project_id": "gateway-demo-243723",
      "timestamp": "2022-10-25T13:31:17",
      "zone": "ZONE_NAME"
    }
    
  3. store.example.com/de にあるドイツ語版のストアサービスにアクセスして、パスの照合をテストします。

    curl -H "host: store.example.com" VIP/de
    

    出力で、リクエストが store-german Pod で処理されたことを確認できます。

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "Gutentag!", 
      "node_name": "gke-gke1-pool-2-bd121936-n3xn.c.gateway-demo-243723.internal",
      "pod_name": "store-german-5cb6474c55-lq5pl", 
      "pod_name_emoji": "🧞‍♀",
      "project_id": "gateway-demo-243723",
      "timestamp": "2022-10-25T13:35:37",
      "zone": "ZONE_NAME"
    }
    
  4. 最後に、env: canary HTTP ヘッダーを使用して、ストアの Service のカナリア バージョンにトラフィックを送信します。

    curl -H "host: store.example.com" -H "env: canary " VIP
    

    出力で、リクエストが store-v2 Pod で処理されたことを確認できます。

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "store-v2", 
      "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.gateway-demo-243723.internal",
      "pod_name": "store-v2-5788476cbd-s9thb", 
      "pod_name_emoji": "🦰",
      "project_id": "gateway-demo-243723",
      "timestamp": "2022-10-25T13:38:26",
      "zone": "ZONE_NAME"
    }
    

外部 Gateway をデプロイする

外部 Gateway は、インターネットまたは VPC 外のネットワークから到達可能なアプリケーションを公開します。これは内部 Gateway のデプロイと似ていますが、Gateway が公共のインターネットにアクセスできるため、アプリケーションを保護する必要があります。

外部 Gateway を作成する場合、グローバル外部 Gateway を作成する方法とリージョン外部 Gateway を作成する方法があります。

グローバル外部 Gateway は、すべての Google Cloud Compute リージョンでアドバタイズされる Gateway のフロントエンドとしてグローバル IP アドレス(またはエニーキャスト IP アドレス)を使用します。このエニーキャスト IP アドレスにトラフィックを送信するクライアントは、IP がアドバタイズされている最も近い Google ロケーションにルーティングされます。グローバル外部 Gateway は、プレミアム ネットワーク サービス ティアでのみ使用できます。

リージョン外部 Gateway は、リージョン外部 Gateway がデプロイされているローカル Google Cloud Compute リージョンでのみアドバタイズされる Gateway のフロントエンドとしてリージョン IP を使用します。このリージョン IP アドレスにトラフィックを送信するクライアントは、ローカル ISP とインターネット経由でルーティングされてから、IP がアドバタイズされている Google リージョンに到達します。リージョン外部 Gateway は、スタンダード ネットワーク サービス ティアでのみ使用できます。

グローバル外部 Gateway をデプロイする

次の例は、グローバル外部 Gateway に関連付けられ、Certificate Manager と HTTPRoute を使用して証明書マップにグループ化された複数の証明書を持つストア アプリケーションを公開する方法を示しています。

証明書マップを作成する

Gateway ごとに 15 個以上の証明書が必要な場合や、ワイルドカード証明書を使用する必要がある場合は、Certificate Manager を使用して証明書を管理することをおすすめします。

Kubernetes Secret または Google マネージド SSL 証明書を使用して外部 Gateway を保護することもできます。詳細については、Gateway のセキュリティをご覧ください。

このセクションでは、Certificate Manager を使用して証明書を作成し、クラスタ上で実行されるアプリケーションを保護します。

  1. Certificate Manager API を有効にします。

    gcloud services enable certificatemanager.googleapis.com
    
  2. 証明書マップを作成します。

    gcloud beta certificate-manager maps create store-example-com-map
    
  3. Google マネージド証明書と鍵を証明書に読み込みます。

    gcloud beta certificate-manager certificates create store-example-com-cert \
        --certificate-file="CERTIFICATE_FILE" \
        --private-key-file="PRIVATE_KEY_FILE"
    

    次のように置き換えます。

    • CERTIFICATE_FILE: 選択した新しいファイルの名前。ファイルの拡張子は .pem にする必要があります。例: cert.pem
    • PRIVATE_KEY_FILE: 秘密鍵ファイルの名前。

    詳細については、秘密鍵と証明書を作成するをご覧ください。

  4. CertificateMapEntry を作成します。これにより、証明書を証明書マップに割り当てます。

    gcloud beta certificate-manager maps entries create store-example-com-map-entry \
        --map=store-example-com-map \
        --hostname=store.example.com \
        --certificates=store-example-com-cert
    

Kubernetes Secret や SSL 証明書など、証明書の他のソースを使用して Gateway を保護する方法については、Gateway を保護するをご覧ください。

Gateway を作成する

Gateway リソースは、Kubernetes のトラフィックをルーティングするデータプレーンを表します。Gateway は、使用する GatewayClass に応じて、さまざまなロード バランシングとルーティングを表すことができます。

Gateway リソースの詳細については、Gateway リソースの説明または API 仕様をご覧ください。

このセクションでは、Gateway を作成します。アプリケーション チームは、Route を個別にデプロイして Gateway に安全に接続することで、Gateway を使用してアプリケーションをインターネットに公開できます。

  1. 次のマニフェストを gateway.yaml という名前のファイルに保存します。

    kind: Gateway
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: external-http
      annotations:
        networking.gke.io/certmap: store-example-com-map
    spec:
      gatewayClassName: gke-l7-global-external-managed
      listeners:
      - name: https
        protocol: HTTPS
        port: 443
    
    

    このマニフェストでは、次のフィールドを使用して Gateway を記述しています。

    • gatewayClassName: gke-l7-global-external-managed: この Gateway の GatewayClass を指定します。このゲートウェイ クラスは、グローバル外部アプリケーション ロードバランサを使用します。
    • protocol: HTTPSport: 443: Gateway が HTTPS トラフィック用にポート 443 を公開することを指定します。これらのフィールドにより TLS が有効になります。
    • networking.gke.io/certmap: store-example-com-map: Certificate Manager の証明書マップの名前を指定します。

    TLS はアノテーション networking.gke.io/certmap を使用して Certificate Manager で構成されるため、TLS セクションはありません。

  2. マニフェストをクラスタに適用します。

    kubectl apply -f gateway.yaml
    

    GKE がリソースをデプロイするまでに数分かかることがあります。

  3. Gateway のデプロイが成功したことを確認します。

    kubectl describe gateway
    

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

    Name:         external-http
    Namespace:    default
    Labels:       <none>
    ...
    Spec:
      Gateway Class Name:  gke-l7-global-external-managed
      Listeners:
        Allowed Routes:
          Namespaces:
            From:  Same
        Name:      https
        Port:      443
        Protocol:  HTTPS
        Tls:
          Certificate Refs:
            Group:
            Kind:   Secret
            Name:   store-example-com
          Mode:     Terminate
     ...
    

    この出力は、クラスタにデプロイされた Gateway にロードバランサとパブリック IP アドレスがあることを示しています。Gateway には Route がありません。つまり、バックエンドにトラフィックを送信できません。Route を使用しないと、すべてのトラフィックがデフォルトのバックエンドに転送され、HTTP 404 レスポンスが返されます。次のセクションでは Route をデプロイして、バックエンドにトラフィックを送信するように Gateway に指示します。

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

アプリケーション チームは、Gateway のデプロイとは別にアプリケーションと Route をデプロイできます。アプリケーション チームで Gateway を所有し、アプリケーション専用のリソースとしてデプロイすることもできます。Gateway と Route のさまざまな所有権モデルについては、Route のバインディングをご覧ください。この例では、ストアチームがアプリケーションと付属の HTTPRoute をデプロイし、前のセクションで作成した external-http Gateway 経由でアプリを公開します。

HTTPRoute フィールドの詳細については、API 仕様をご覧ください。

  1. サンプル アプリケーションをクラスタにデプロイします。

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/store.yaml
    

    このサンプル アプリケーションは、store-v1store-v2store-german という名前の 3 つの Deployment と 3 つの Service を作成します。

  2. アプリケーションのデプロイが成功したことを確認します。

    kubectl get pod
    

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

    NAME                            READY   STATUS    RESTARTS   AGE
    store-german-66dcb75977-5gr2n   1/1     Running   0          38s
    store-v1-65b47557df-jkjbm       1/1     Running   0          14m
    store-v2-6856f59f7f-sq889       1/1     Running   0          14m
    
  3. Service が正常にデプロイされたことを確認します。

    kubectl get service
    

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

    NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
    store-german   ClusterIP   10.48.3.183   <none>        8080/TCP   4s
    store-v1       ClusterIP   10.48.2.224   <none>        8080/TCP   5s
    store-v2       ClusterIP   10.48.4.48    <none>        8080/TCP   5s
    

HTTPRoute を作成する

Route リソースは、Gateway から Kubernetes バックエンドにトラフィックをマッピングするためのプロトコル固有のルールを定義します。HTTPRoute リソースは、HTTP および HTTPS トラフィックの照合とフィルタリングを行います。これは、すべての gke-l7-* GatewayClass でサポートされています。

このセクションでは、HTTPRoute をデプロイします。これにより、サンプル アプリケーションに到達するために必要なルーティング ルールで Gateway が構成されます。

  1. 次のマニフェストを store-route-external.yaml という名前のファイルに保存します。

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-external
    spec:
      parentRefs:
      - kind: Gateway
        name: external-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - name: store-v1
          port: 8080
      - matches:
        - headers:
          - name: env
            value: canary
        backendRefs:
        - name: store-v2
          port: 8080
      - matches:
        - path:
            value: /de
        backendRefs:
        - name: store-german
          port: 8080
    

    このマニフェストでは、external-http Gateway を参照する HTTPRoute を記述しています。

  2. マニフェストをクラスタに適用します。

    kubectl apply -f store-route-external.yaml
    

    store HTTPRoute は parentRefs プロパティを使用して external-http Gateway にバインドされます。次の図は、基盤となるロードバランサで構成されたルーティング ルールを示しています。

    ストアの HTTPRoute によって構成されたルーティング ルール

    ルーティング ルールは、HTTP トラフィックを次のように処理します。

    • store.example.com/de へのトラフィックは Service store-german に転送されます。
    • HTTP ヘッダー "env: canary" を含む store.example.com へのトラフィックは、Service store-v2 に転送されます。
    • store.example.com への残りのトラフィックは、Service store-v1 に転送されます。
  3. HTTPRoute がデプロイされていることを確認します。

    kubectl describe httproute store-external
    

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

    Name:         store-external
    Namespace:    default
    Labels:       <none>
    Annotations:  <none>
    API Version:  gateway.networking.k8s.io/v1beta1
    Kind:         HTTPRoute
    <...>
    Spec:
      Hostnames:
        store.example.com
      Parent Refs:
        Group:  gateway.networking.k8s.io
        Kind:   Gateway
        Name:   external-http
      Rules:
        Backend Refs:
          Group:
          Kind:    Service
          Name:    store-v1
          Port:    8080
          Weight:  1
        Matches:
          Path:
            Type:   PathPrefix
            Value:  /
        Backend Refs:
          Group:
          Kind:    Service
          Name:    store-v2
          Port:    8080
          Weight:  1
        Matches:
          Headers:
            Name:   env
            Type:   Exact
            Value:  canary
          Path:
            Type:   PathPrefix
            Value:  /
        Backend Refs:
          Group:
          Kind:    Service
          Name:    store-german
          Port:    8080
          Weight:  1
        Matches:
          Path:
            Type:   PathPrefix
            Value:  /de
    Status:
      Parents:
        Conditions:
          Last Transition Time:  2022-11-01T05:42:31Z
          Message:
          Reason:                Accepted
          Status:                True
          Type:                  Accepted
          Last Transition Time:  2022-11-01T05:43:18Z
          Message:
          Reason:                ReconciliationSucceeded
          Status:                True
          Type:                  Reconciled
        Controller Name:         networking.gke.io/gateway
        Parent Ref:
          Group:  gateway.networking.k8s.io
          Kind:   Gateway
          Name:   external-http
    Events:
      Type     Reason  Age    From                   Message
      ----     ------  ----   ----                   -------
      Normal   ADD     2m48s  sc-gateway-controller  default/store-external
      Normal  SYNC  61s (x3 over 2m27s)  sc-gateway-controller  Bind of HTTPRoute "default/store-external" to ParentRef Group:       "gateway.networking.k8s.io",
      ...
    
  4. HTTPRoute が Gateway にバインドされていることを確認します。

    kubectl describe gateway external-http
    

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

    Name:         external-http
    Namespace:    default
    Labels:       <none>
    <...>
    Status:
      Addresses:
        Type:   IPAddress
        Value:  34.149.207.45
      Conditions:
        Last Transition Time:  2022-11-01T05:37:21Z
        Message:
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
        Last Transition Time:  2022-11-01T05:43:18Z
        Message:
        Reason:                Ready
        Status:                True
        Type:                  Ready
      Listeners:
        Attached Routes:  1
        Conditions:
          Last Transition Time:  2022-11-01T05:43:18Z
          Message:
          Reason:                Ready
          Status:                True
          Type:                  Ready
        Name:                    https
        Supported Kinds:
          Group:  gateway.networking.k8s.io
          Kind:   HTTPRoute
          <...>
    

アプリケーションにトラフィックを送信する

クラスタに Gateway、Route、アプリケーションがデプロイされたので、アプリケーションにトラフィックを送信してみましょう。

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

    kubectl get gateways.gateway.networking.k8s.io external-http -o=jsonpath="{.status.addresses[0].value}"
    

    出力は IP アドレスです。

  2. VM を作成します。

    gcloud cloud-shell ssh
    
  3. VM から Gateway IP アドレスにトラフィックを送信します。example.com ホスト名を所有していないため、host ヘッダーを手動で設定する必要があります。

    curl -H "host: store.example.com" https://GATEWAY_IP_ADDRESS --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert cacert.pem -v
    

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

    出力には、アプリの実場所に関するデモアプリからの情報が表示されます。

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.gateway-demo-243723.internal",
      "pod_name": "store-v1-84b47c7f58-pmgmk",
      "pod_name_emoji": "💇🏼‍♀️",
      "project_id": "gateway-demo-243723",
      "timestamp": "2022-09-25T13:31:17",
      "zone": "us-central1-a"
    }
    
  4. store.example.com/de にあるドイツ語版の store サービスにアクセスして、パスの照合をテストします。

    curl -H "host: store.example.com" https://GATEWAY_IP_ADDRESS/de --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert cacert.pem -v
    

    出力で、リクエストが store-german Pod で処理されたことを確認できます。

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "Gutentag!",
      "node_name": "gke-gke1-pool-2-bd121936-n3xn.c.gateway-demo-243723.internal",
      "pod_name": "store-german-5cb6474c55-lq5pl",
      "pod_name_emoji": "🧞‍♀",
      "project_id": "gateway-demo-243723",
      "timestamp": "2022-09-25T13:35:37",
      "zone": "us-central1-a"
    }
    
  5. env: canary HTTP ヘッダーを使用して、store Service のカナリア バージョンにトラフィックを送信します。

    curl -H "host: store.example.com" -H "env: canary " https://GATEWAY_IP_ADDRESS/de --resolve store.example.com:443:GATEWAY_IP_ADDRESS --cacert cacert.pem -v
    

    出力で、リクエストが store-v2 Pod で処理されたことを確認できます。

    {
      "cluster_name": "gke1",
      "host_header": "store.example.com",
      "metadata": "store-v2",
      "node_name": "gke-gke1-pool-2-bd121936-5pfc.c.gateway-demo-243723.internal",
      "pod_name": "store-v2-5788476cbd-s9thb",
      "pod_name_emoji": "👩🏿",
      "project_id": "gateway-demo-243723",
      "timestamp": "2022-09-25T13:38:26",
      "zone": "us-central1-a"
    }
    

リージョン外部 Gateway をデプロイする

次の例は、セルフマネージド証明書と HTTPRoute を使用して、リージョン外部 Gateway に関連付けられた複数の証明書を持つストア アプリケーションを公開する方法を示しています。

リージョン Gateway のプロキシ サブネットを作成する

リージョン外部アプリケーション ロードバランサを使用する Gateway を作成する前に、プロキシ専用サブネットを構成する必要があります。リージョン外部アプリケーション ロードバランサを使用する VPC の各リージョンには、external_managed_proxy サブネットが必要です。このサブネットは、ロードバランサ プロキシに内部 IP アドレスを提供します。

証明書を作成してクライアント トラフィックを保護する

認証局(CA)から発行された検証済みの証明書を使用するか、自己署名証明書を作成できます。証明書の作成方法の詳細については、Kubernetes Secret に証明書を保存するをご覧ください。

リージョン外部 HTTP(S) Gateway を作成する

  1. 外部ロードバランサのリージョン静的 IP アドレスを作成します。

    gcloud compute addresses create IP_ADDRESS_NAME \
      --region=COMPUTE_REGION \
      --network-tier=STANDARD
    

    次のように置き換えます。

    • IP_ADDRESS_NAME: 新しい静的 IP アドレスの名前。
    • COMPUTE_REGION: クラスタが動作している Compute Engine リージョン。
  2. 次のようにセルフマネージド証明書を使用して、リージョン外部アプリケーション ロードバランサの Gateway を作成し、マニフェストを regional-gateway.yaml として保存します。

      kind: Gateway
      apiVersion: gateway.networking.k8s.io/v1beta1
      metadata:
        name: external-regional-http
      spec:
        gatewayClassName: gke-l7-regional-external-managed
        listeners:
        - name: https
          protocol: HTTPS
          port: 443
          tls:
            mode: Terminate
            certificateRefs:
            - name: store-example-com
        addresses:
        - type: NamedAddress
          value: IP_ADDRESS_NAME
    
  3. regional-gateway マニフェストを適用します。

      kubectl apply -f regional-gateway.yaml
    
  4. 構成を確認します。

      kubectl get gateway
    

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

    NAME            CLASS                              ADDRESS         READY   AGE
    external-http   gke-l7-regional-external-managed   35.118.32.224   True    49s
    

    詳細を取得するには、describe コマンドを使用します。

    kubectl describe gateway
    

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

    Name:         external-regional-http
    Namespace:    default
    Labels:       <none>
    ...
    Spec:
      Gateway Class Name:  gke-l7-regional-external-managed
      Listeners:
        Allowed Routes:
          Namespaces:
            From:  Same
        Name:      https
        Port:      443
        Protocol:  HTTPS
        Tls:
          Certificate Refs:
            Group:
            Kind:   Secret
            Name:   store-example-com
          Mode:     Terminate
      ...
    

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

Gateway のデプロイとは別に、アプリケーションとルートをデプロイできます。

デモ アプリケーションのデプロイ方法については、デモ アプリケーションをデプロイするをご覧ください。

HTTPRoute を作成する

HTTP および HTTPS トラフィックの照合とフィルタリングを行うには、HTTPRoute を作成する必要があります。

アプリケーションにトラフィックを送信する

アプリケーションをデプロイして HTTPRoute を作成したら、アプリケーションにトラフィックを渡すことができます。

アプリケーションにトラフィックを送信する方法については、アプリケーションにトラフィックを送信するをご覧ください。

共有 Gateway を使用する

Gateway API は、個別のリソース、Gateway と Route のリソースを使用して、ロードバランサとルーティング ルールをデプロイします。Ingress とは異なり、1 つのリソースにすべてが結合されます。リソース間で責任を分担することにより、Gateway でロードバランサとルーティング ルールを別々にデプロイすることが可能になります。これらは、異なるユーザーまたはチームがデプロイすることもできます。これにより、Gateway を複数の異なる Route で接続される共有 Gateway にし、Namespace が異なる場合でも、個々のチームで完全に所有し、管理できるようになります。

共有 Gateway に対するルートをデプロイする

この例は、内部 Gateway のデプロイでデプロイした internal-http Gateway を基盤としています。

この例では、サイトチームがアプリケーション、Service、HTTPRoute をデプロイして、Gateway からこれらの Service へのトラフィックを照合します。

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

    kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/gke-networking-recipes/main/gateway/gke-gateway-controller/app/site.yaml
    
  2. 次のマニフェストを site-route-internal.yaml という名前のファイルに保存します。

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: site-internal
    spec:
      parentRefs:
      - kind: Gateway
        name: internal-http
      hostnames:
      - "site.example.com"
      rules:
      - backendRefs:
        - name: site-v1
          port: 8080
    

    このマニフェストでは、site.example.com のすべてのトラフィックを照合し、一致したものを site-v1 Service にルーティングする HTTPRoute を記述しています。

  3. マニフェストをクラスタに適用します。

    kubectl apply -f site-route-internal.yaml
    
  4. HTTPRoute が Gateway に接続されていることを確認します。

    kubectl describe httproute.gateway.networking.k8s.io site-internal
    

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

    Status:
      Parents:
        Conditions:
          Last Transition Time:  2023-01-09T15:05:43Z
          Message:
          Reason:                Accepted
          Status:                True
          Type:                  Accepted
          Last Transition Time:  2023-01-09T15:05:43Z
          Message:
          Reason:                ReconciliationSucceeded
          Status:                True
          Type:                  Reconciled
        Controller Name:         networking.gke.io/gateway
        Parent Ref:
          Group:  gateway.networking.k8s.io
          Kind:   Gateway
          Name:   internal-http
          ...
    

    Gateway の Accepted 条件が True の場合、HTTPRoute は Gateway に正常にバインドされています。[Status] フィールドの詳細については、ルートのステータスをご覧ください。

  5. Gateway へのトラフィックが正しくルーティングされていることを確認します。

    curl -H "host: site.example.com" GATEWAY_IP_ADDRESS
    curl -H "host: store.example.com" GATEWAY_IP_ADDRESS
    

    GATEWAY_IP_ADDRESS は、Gateway の IP アドレスに置き換えます。

    Gateway と同じ VPC で仮想マシン(VM)を使用する必要があります。

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

    {
      "cluster_name": "CLUSTER_NAME",
      "host_header": "site.example.com",
      "metadata": "site-v1",
      "pod_name": "site-v1-5d64fc4d7d-fz6f6",
      "pod_name_emoji": "👩🏼‍🍳",
      "project_id": "PROJECT_ID",
      "timestamp": "2022-11-02T19:07:01",
      "zone": "ZONE_NAME"
    }
    ...
    {
      "cluster_name": "CLUSTER_NAME",
      "host_header": "store.example.com",
      "metadata": "store-v1",
      "pod_name": "store-v1-6d8d58d78-vz8pn",
      "pod_name_emoji": "🧝🏻‍♂️",
      "project_id": "PROJECT_ID",
      "timestamp": "2022-11-02T19:07:01",
      "zone": "ZONE_NAME"
    }
    

Gateway のデフォルト バックエンドを構成する

すべての gke-l7-* GatewayClass は、一致しないトラフィックに対して HTTP 404 を返します。一致しないトラフィックをユーザー指定の Service に送信する明示的なデフォルト Route を使用して、デフォルト バックエンドを構成できます。

次の HTTPRoute は、デフォルトのバックエンドをカスタマイズする方法の一例です。次のような HTTPRoute を適用すると、暗黙的なデフォルト バックエンドよりも優先されます。

kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1beta1
metadata:
  name: custom-default-backend
spec:
  parentRefs:
  - kind: Gateway
    name: my-internal-gateway
  rules:
  - backendRefs:
    - name: my-custom-default-backend-service
      port: 8080

この HTTPRoute は特定の Gateway のすべてのトラフィックに一致します。このようなルールは Gateway ごとに 1 つだけ設定できます。そうでない場合は、ルールが競合して優先順位が適用されます。

デフォルトのバックエンドを使用して、すべての Gateway トラフィックをルーティングするデフォルト ルートのバックエンドが作成されないようにすることができます。明示的な HTTPRoute は、競合するルーティング ルールを持つ新しい HTTPRoute よりも常に優先されます。

Gateway に静的 IP アドレスを構成する

どの Gateway にもトラフィックのリッスンに使用する IP アドレスがあります。Gateway の IP アドレスを指定しない場合、Gateway コントローラは自動的に IP アドレスを提供します。Gateway のライフサイクルとは独立して IP アドレスが存在するように、静的 IP アドレスを作成することもできます。

Gateway がデプロイされると、ステータス フィールドにその IP アドレスが表示されます。

kind: Gateway
...
status:
  addresses:
    - value: 10.15.32.3

GatewayClass に応じて、IP アドレスは次のサブネットから割り振られます。

GatewayClass デフォルトの IP アドレスプール
  • gke-l7-rilb
  • gke-l7-rilb-mc
  • プライマリ ノードの IPv4 / IPv6 アドレス範囲のリージョン プライベート IP アドレス
  • gke-l7-regional-external-managed
  • gke-l7-regional-external-managed-mc
  • Google のリージョン外部 IPv4 / IPv6 範囲のリージョン パブリック IP アドレス
  • gke-l7-global-external-managed
  • gke-l7-global-external-managed-mc
  • gke-l7-gxlb
  • gke-l7-gxlb-mc
  • Google のグローバル外部 IPv4 / IPv6 範囲のグローバル パブリック IP アドレス

    addresses.NamedAddress フィールドを使用すると、Gateway とは無関係に IP アドレスを指定できます。Gateway のデプロイ前に静的 IP アドレス リソースを作成できます。これらのリソースは、NamedAddress によって参照されます。Gateway が削除されても、静的 IP アドレスは再利用できます。

    名前付き IP アドレスを使用する

    IP アドレスを構成するには、NamedAddress を指定します。Gateway を作成する前に、静的 IP アドレスをプロビジョニングする必要があります。

    1. 静的 IP アドレス リソースを作成します。

      gcloud compute addresses create IP_ADDRESS_NAME \
          --purpose=SHARED_LOADBALANCER_VIP \
          --region=COMPUTE_REGION \
          --subnet=SUBNET \
          --project=PROJECT_ID
      

      次のように置き換えます。

      • IP_ADDRESS_NAME: 新しい静的 IP アドレスの名前
      • COMPUTE_REGION: リージョン Gateway の場合、クラスタが動作している Compute Engine リージョン。 このフラグは、グローバル外部 Gateway には必要ありません。
      • SUBNET: IP アドレスのサブネット。 このフラグは、グローバル外部 Gateway には必要ありません。
      • PROJECT_ID: GKE クラスタが実行されているプロジェクト。
    2. 次のマニフェストを named-ip-gateway.yaml という名前のファイルに保存します。

      kind: Gateway
      apiVersion: gateway.networking.k8s.io/v1beta1
      metadata:
        name: internal-http
      spec:
        gatewayClassName: gke-l7-rilb
        listeners:
        - name: http
          protocol: HTTP
          port: 80
        addresses:
        - type: NamedAddress
          value: IP_ADDRESS_NAME
      

      このマニフェストでは、指定された IP アドレスを参照する Gateway を記述しています。

    3. マニフェストをクラスタに適用します。

      kubectl apply -f named-ip-gateway.yaml
      
    4. Gateway の IP アドレスを確認します。

      kubectl describe gateway internal-http
      

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

      Name:         internal-http
      Namespace:    default
      Labels:       <none>
      ...
      Spec:
        Addresses:
          Type:              NamedAddress
          Value:             IP_ADDRESS_NAME
        Gateway Class Name:  gke-l7-rilb
        Listeners:
          Allowed Routes:
            Namespaces:
              From:  Same
          Name:      http
          Port:      80
          Protocol:  HTTP
      Status:
        Addresses:
          Type:   IPAddress
          Value:  10.15.32.103
      

    HTTP から HTTPS へのリダイレクトを構成する

    Cloud Load Balancing には、HTTP から HTTPS へのリダイレクト機能が用意されています。外部アプリケーション ロードバランサは、同じ IP アドレスを使用する HTTPS ロードバランサに、暗号化されていない HTTP リクエストをリダイレクトします。HTTP から HTTPS へのリダイレクトを有効にして Gateway を作成すると、この両方のロードバランサが自動的に作成されます。ポート 80 の Gateway の外部 IP アドレスへのリクエストは、ポート 443 の同じ外部 IP アドレスに自動的にリダイレクトされます。

    デフォルトでは、HTTP から HTTPS へのリダイレクトは Gateway で定義されていません。

    HTTP トラフィックを HTTPS にリダイレクトするには、HTTP と HTTPS の両方のトラフィックを処理するように Gateway を構成します。HTTP または HTTPS を無効にすると、Gateway はトラフィックをリダイレクトしません。

    次の例では、クライアントからウェブ アプリケーションに向うトラフィックが常に安全なページにリダイレクトされるようにするために、HTTP から HTTPS へのリダイレクトを使用する方法を示します。

    Gateway Namespace からの HTTP トラフィックをリダイレクトする

    次の例では、HTTPS リスナーがすべての Namespace に対して開かれている間、HTTP リスナーで Same(同じ Namespace からのアタッチメント)を許可するように Gateway が構成されています。この構成を使用する場合、リダイレクト HTTPRoute のみを Gateway と同じ Namespace に置く必要があります。

    この構成により、追加の HTTPRoute が Gateway の HTTP リスナーにバインドされないことが保証されます。そのためには、アプリケーション チームの HTTPRoute を gateway-infra Namespace で許可しないようにする必要があります。

    1. Gateway の Namespace gateway-infra を作成します。マニフェストを gateway-namespace.yaml として保存します。

      apiVersion: v1
      kind: Namespace
      metadata:
        name: gateway-infra
      
    2. 次のようにマニフェストを適用します。

      kubectl apply -f gateway-namespace.yaml
      
    3. 次のマニフェストを使用して Gateway を作成し、マニフェストを external-gateway.yaml として保存します。

      kind: Gateway
      apiVersion: gateway.networking.k8s.io/v1beta1
      metadata:
        name: external-http
        namespace: gateway-infra
      spec:
        gatewayClassName: gke-l7-global-external-managed
        listeners:
        - name: http
          protocol: HTTP
          port: 80
          allowedRoutes:
            kinds:
            - kind: HTTPRoute
            namespaces:
              from: Same
        - name: https
          protocol: HTTPS
          port: 443
          allowedRoutes:
            kinds:
            - kind: HTTPRoute
            namespaces:
              from: All
          tls:
            mode: Terminate
            options:
              networking.gke.io/pre-shared-certs: store-example-com
      
      • allowedRoutes セクションの namespaces フィールドは、HTTP リスナーを Gateway の Namespace gateway-infra のみに制限します。

      • https リスナーには、許可される Namespace に対する制限が含まれていないため、すべての Namespace で HTTPRoute とともに https リスナーを使用します。

    4. 次のようにマニフェストを適用します。

      kubectl apply -f external-gateway.yaml
      
    5. HTTPS リダイレクトを強制するには、次のマニフェストを使用してデフォルトの HTTPRoute を作成し、マニフェストを redirect-httproute.yaml として保存します。

      kind: HTTPRoute
      apiVersion: gateway.networking.k8s.io/v1beta1
      metadata:
        name: redirect
        namespace: gateway-infra
      spec:
        parentRefs:
        - namespace: gateway-infra
          name: external-http
          sectionName: http
        rules:
        - filters:
          - type: RequestRedirect
            requestRedirect:
              scheme: https
      
      • sectionName フィールドは、http リスナーのみで照合するように Gateway に指示します。RequestRedirect フィルタは、https リスナーへのリダイレクトを強制します。

      この構成では、Gateway のポート 80 で受信したトラフィックをポート 443 のリスナーにリダイレクトし、クライアントとロードバランサの間で安全な通信を実現します。

    6. 次のようにマニフェストを適用します。

      kubectl apply -f redirect-httproute.yaml
      
    7. 次のマニフェストを使用して、アプリケーションの Service を作成します。マニフェストを service-deployment.yaml として保存します。

      apiVersion: v1
      kind: Service
      metadata:
        name: store-v1
      spec:
        selector:
          app: store
          version: v1
        ports:
        - port: 8080
          targetPort: 8080
      
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: store-v1
      spec:
        replicas: 2
        selector:
          matchLabels:
            app: store
            version: v1
        template:
          metadata:
            labels:
              app: store
              version: v1
          spec:
            containers:
            - name: whereami
              image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1.2.20
              ports:
              - containerPort: 8080
              env:
              - name: METADATA
                value: "store-v1"
      
    8. 次のようにマニフェストを適用します。

      kubectl apply -f service-deployment.yaml
      
    9. HTTPS のみを許可するアプリケーションに HTTPRoute を作成します。マニフェストを httproute.yaml として保存します。

      kind: HTTPRoute
      apiVersion: gateway.networking.k8s.io/v1beta1
      metadata:
        name: store-external
        labels:
          gateway: external-http
      spec:
        parentRefs:
        - name: external-http
          namespace: gateway-infra
          sectionName: https
        hostnames:
        - "store.example.com"
        rules:
        - backendRefs:
          - name: store-v1
            port: 8080
      
    10. 次のようにマニフェストを適用します。

      kubectl apply -f httproute.yaml
      

    インフラストラクチャ Namespace からの HTTP トラフィックをリダイレクトする

    場合によっては、インフラストラクチャやプラットフォームの管理チームとアプリケーション チームとの間に明確な違いがなく、Gateway の誤用防止が課題になることがあります。

    次の例では、HTTP リスナーの使用をさらに制限して、アプリケーション チームが誤ってセキュアでないプロトコルを使用しないようにします。この例では、ルートが特定の Namespace(http-redirect)にある場合にのみ HTTPRoute が HTTP リスナーを使用できるようにし、すべての Namespace に対して HTTPS リスナーを開くように Gateway を構成します。Kubernetes RBAC を使用して http-redirect Namespace を制限することで、アプリケーション チームが誤ってこの Namespace に HTTPRoute を作成しないようにします。

    1. Gateway の Namespace を作成し、マニフェストを gateway-namespace.yaml として保存します。

      apiVersion: v1
      kind: Namespace
      metadata:
        name: gateway-infra
      
    2. 次のようにマニフェストを適用します。

      kubectl apply -f gateway-namespace.yaml
      
    3. Gateway の Namespace を作成し、マニフェストを redirect-namespace.yaml として保存します。

      apiVersion: v1
      kind: Namespace
      metadata:
        name: http-redirect
        labels:
          otherInfra: httpToHttps
      
      • この Namespace には特定のラベルが設定されています。
    4. 次のようにマニフェストを適用します。

      kubectl apply -f redirect-namespace.yaml
      
    5. HTTP リスナーの使用を制限するには、次のマニフェストを使用して Gateway を作成します。マニフェストを external-gateway.yaml として保存します。

      kind: Gateway
      apiVersion: gateway.networking.k8s.io/v1beta1
      metadata:
        name: external-http
        namespace: gateway-infra
      spec:
        gatewayClassName: gke-l7-global-external-managed
        listeners:
        - name: http
          protocol: HTTP
          port: 80
          allowedRoutes:
            kinds:
            - kind: HTTPRoute
            namespaces:
              from: selector
              selector:
                matchLabels:
                  otherInfra: httpToHttps
        - name: https
          protocol: HTTPS
          port: 443
          allowedRoutes:
            kinds:
            - kind: HTTPRoute
            namespaces:
              from: All
          tls:
            mode: Terminate
            options:
              networking.gke.io/pre-shared-certs: store-example-com
        ```
      
      • namespace フィールドには、Gateway が gateway-infra Namespace に作成されることを指定します。

      • allowedRoutes セクションの namespaces フィールドは、HTTP リスナーをラベル otherInfra: httpToHttps と一致する Namespace に制限します。

    6. 次のようにマニフェストを適用します。

      kubectl apply -f external-gateway.yaml
      
    7. HTTPS リダイレクトを強制するには、次のマニフェストを使用してデフォルトの HTTPRoute を作成します。マニフェストを http-redirect.yaml として保存します。

      kind: HTTPRoute
      apiVersion: gateway.networking.k8s.io/v1beta1
      metadata:
        name: redirect
        namespace: http-redirect
      spec:
        parentRefs:
        - namespace: gateway-infra
          name: external-http
          sectionName: http
        rules:
        - filters:
          - type: RequestRedirect
            requestRedirect:
              scheme: https
      
      • sectionName フィールドは、http リスナーのみで照合するように Gateway に指示します。RequestRedirect フィルタは、HTTPS リスナーへのリダイレクトを強制します。
    8. 次のようにマニフェストを適用します。

      kubectl apply -f http-redirect.yaml
      
    9. 次のマニフェストを使用して、アプリケーションの Service を作成します。マニフェストを service-deployment.yaml として保存します。

      apiVersion: v1
      kind: Service
      metadata:
        name: store-v1
      spec:
        selector:
          app: store
          version: v1
        ports:
        - port: 8080
          targetPort: 8080
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: store-v1
      spec:
        replicas: 2
        selector:
          matchLabels:
            app: store
            version: v1
        template:
          metadata:
            labels:
              app: store
              version: v1
          spec:
            containers:
            - name: whereami
              image: us-docker.pkg.dev/google-samples/containers/gke/whereami:v1.2.20
              ports:
              - containerPort: 8080
              env:
              - name: METADATA
                value: "store-v1"
      
    10. 次のようにマニフェストを適用します。

      kubectl apply -f service-deployment.yaml
      
    11. 次のマニフェストを使用して、HTTPS のみを許可するアプリケーションに HTTPRoute を作成します。マニフェストを http-route.yaml として保存します。

      kind: HTTPRoute
      apiVersion: gateway.networking.k8s.io/v1beta1
      metadata:
        name: store-external
        labels:
          gateway: external-http
      spec:
        parentRefs:
        - name: external-http
          namespace: gateway-infra
          sectionName: https
        hostnames:
        - "store.example.com"
        rules:
        - backendRefs:
          - name: store-v1
            port: 8080
      
    12. 次のようにマニフェストを適用します。

      kubectl apply -f http-route.yaml
      

    パス リダイレクトと URL の書き換えを構成する

    パス リダイレクトを使用すると、受信リクエストを 1 つの URL パスから別の URL パスにリダイレクトできます。パス リダイレクトを使用すると、古い URL や非推奨の URL を処理する必要がある場合に URL の構造を変更できます。

    URL の書き換えは、受信 URL を変更してからサーバーで処理する場合に役立ちます。これにより、基になるコンテンツやファイル構造を実際に変更することなく、URL の構造や形式を変更できます。URL の書き換えは、覚えやすく理解しやすい、ユーザー フレンドリーで SEO に適した URL を作成するのに便利です。デフォルトでは、パス リダイレクトと URL の書き換えは構成されていません。HTTPRoute のフィルタを使用して、これらのリダイレクトまたは書き換えを明示的に構成する必要があります。

    GKE Gateway はパス リダイレクトと URL の書き換えをサポートしています。詳細については、HTTP パス リダイレクトと書き換えをご覧ください。

    パス リダイレクトを構成する

    パス リダイレクトを構成して、パス全体または URL 内の接頭辞のみを置き換えることができます。

    パス全体を置き換える

    1. パス全体を置き換えるには、URL パスに接頭辞 /any-path を含む任意の URL を厳格な値 /new-path に置き換えるフィルタを HTTPRoute に構成します。

    2. 次のように HTTPRoute マニフェストを作成し、store.yaml という名前を付けます。

        apiVersion: gateway.networking.k8s.io/v1beta1
        kind: HTTPRoute
        metadata:
          name: store
        spec:
          parentRefs:
            - kind: Gateway
              name: external-http
          hostnames:
          - store.example.com
          rules:
          - matches:
            - path:
                type: PathPrefix
                value: /any-path
            filters:
            - type: RequestRedirect
              requestRedirect:
                path:
                  type: ReplaceFullPath
                  replaceFullPath: /new-path
                statusCode: 302
      

      たとえば、このマニフェストでは、URL https://store.example.com/any-path/... へのルートが新しいロケーション https://store.example.com/new-path/ にリダイレクトされるように、HTTPRoute のルーティング ルールを厳格に設定しています。

    3. 次のようにマニフェストを適用します。

      kubectl apply -f store.yaml
      

    このルーティング ルールは厳格なリダイレクト ルールに従っています。ブラウザは、リダイレクトをキャッシュに保存せず、最新バージョンにリダイレクトします。

    接頭辞のみを置き換える

    1. 接頭辞のみを置き換えるには、URL パスに接頭辞 /any-prefix が含まれる URL を厳格な値 /new-prefix に置き換えるフィルタを HTTPRoute に構成します。

    2. 次のように HTTPRoute マニフェストを作成し、store.yaml という名前を付けます。

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: HTTPRoute
      metadata:
        name: store
      spec:
        parentRefs:
          - kind: Gateway
            name: external-http
        hostnames:
        - store.example.com
        rules:
        - matches:
            - path:
                type: PathPrefix
                value: /any-prefix
          filters:
          - type: RequestRedirect
            requestRedirect:
              path:
                type: ReplacePrefixMatch
                replacePrefixMatch: /new-prefix
              statusCode: 302
      

      たとえば、このマニフェストでは、URL https://store.example.com/any-path/v1/... へのルートを新しい場所 https://store.example.com/new-path/v1/... のみにリダイレクトされるように HTTPRoute のルーティング ルールを設定しています。

    3. 次のようにマニフェストを適用します。

        kubectl apply -f store.yaml
      

    このルーティング ルールは、唯一のリダイレクト ルールに従っています。ブラウザは常に同じページにリダイレクトされます。

    URL の書き換えを構成する

    URL の書き換えを設定すると、ユーザーへの URL の表示方法を変更できます。URL の書き換えは、URL をよりユーザー フレンドリーにしたり、SEO を改善するために使用します。また、ユーザーを新しいページにリダイレクトする場合にも使用できます。

    ホスト名全体を書き換える

    ホスト名全体を書き換えるには:

    1. www.example.com から store.example.com へのリクエスト ヘッダーで Host 情報を置き換えるようにゲートウェイに指示するフィルタを HTTPRoute で構成してから、リクエストをバックエンド サービスに転送します。

    2. 次のように HTTPRoute マニフェストを作成し、www.yaml という名前を付けます。

        apiVersion: gateway.networking.k8s.io/v1beta1
        kind: HTTPRoute
        metadata:
          name: www
        spec:
          parentRefs:
            - kind: Gateway
              name: external-http
          hostnames:
          - www.example.com
          rules:
          - filters:
            - type: URLRewrite
              urlRewrite:
                hostname: store.example.com
            backendRefs:
            - name: store-v1
              port: 8080
      

      たとえば、上記の構成では、https://www.example.com へのリクエストは、Host: www.example.com ではなく、Host: store.example.com ヘッダーを有するバックエンド サービスに転送されます。

    3. 次のようにマニフェストを適用します。

        kubectl apply -f www.yaml
      

    パス修飾子を使用して書き換える

    パス修飾子と組み合わせて書き換えを使用すると、リクエストをバックエンド サービスにリレーする前に、URL とパスに対して高度な変更を行うことができます。

    パス修飾子を使用して書き換えるには:

    1. www.example.com から store.example.com へのリクエスト ヘッダーで「ホスト」情報を置き換えるようにゲートウェイが指示するフィルタを HTTPRoute で構成し、値 /store を値 / に置き換えてから、リクエストをバックエンド サービスに転送します。

    2. 次のように HTTPRoute マニフェストを作成し、www.yaml という名前を付けます。

        apiVersion: gateway.networking.k8s.io/v1beta1
        kind: HTTPRoute
        metadata:
          name: www
        spec:
          parentRefs:
            - kind: Gateway
              name: external-http
          hostnames:
          - www.example.com
          rules:
          - matches:
            - path:
                type: PathPrefix
                value: /store
            filters:
            - type: URLRewrite
              urlRewrite:
                hostname: store.example.com
                path:
                  type: ReplacePrefixMatch
                  replacePrefixMatch: /de
            backendRefs:
            - name: store-german
              port: 8080
      

      たとえば、上記の構成では、https://www.example.com/store/... へのリクエストはリクエスト ヘッダーに Host: www.example.com ではなく Host: store.example.com があるバックエンド サービスに転送され、/store/de に書き換えられます。

    3. 次のようにマニフェストを適用します。

      kubectl apply -f www.yaml
      

    構成を確認する

    URL の書き換えフィルタまたはパス リダイレクト フィルタを使用して HTTPRoute の作成後にフィルタが適用されたことを確認するには、次の操作を行います。

    kubectl get httproute www -o yaml
    

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

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: HTTPRoute
      metadata:
        annotations:
          kubectl.kubernetes.io/last-applied-configuration: |
            {"apiVersion":"gateway.networking.k8s.io/v1beta1","kind":"HTTPRoute","metadata":{"annotations":{},"name":"www","namespace":"default"},"spec":{"hostnames":["www.example.com"],"parentRefs":[{"kind":"Gateway","name":"external-http"}],"rules":[{"backendRefs":[{"name":"store-german","port":8080}],"filters":[{"type":"URLRewrite","urlRewrite":{"hostname":"store.example.com","path":{"replacePrefixMatch":"/de","type":"ReplacePrefixMatch"}}}],"matches":[{"path":{"type":"PathPrefix","value":"/store"}}]}]}}
        creationTimestamp: "2023-06-22T01:00:42Z"
        generation: 3
        name: www
        namespace: default
        resourceVersion: "51268631"
        uid: e516493e-806d-44d6-ae0d-1c9ff25682cf
      spec:
        hostnames:
        - www.example.com
        parentRefs:
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: external-http
        rules:
        - backendRefs:
          - group: ""
            kind: Service
            name: store-german
            port: 8080
            weight: 1
          filters:
          - type: URLRewrite
            urlRewrite:
              hostname: store.example.com
              path:
                replacePrefixMatch: /de
                type: ReplacePrefixMatch
          matches:
          - path:
              type: PathPrefix
              value: /store
      status:
        parents:
        - conditions:
          - lastTransitionTime: "2023-06-22T01:11:26Z"
            message: ""
            observedGeneration: 2
            reason: Accepted
            status: "True"
            type: Accepted
          - lastTransitionTime: "2023-06-22T01:11:26Z"
            message: ""
            observedGeneration: 2
            reason: ReconciliationSucceeded
            status: "True"
            type: Reconciled
          controllerName: networking.gke.io/gateway
          parentRef:
            group: gateway.networking.k8s.io
            kind: Gateway
            name: external-http
    
    

    詳細を確認するには、describe コマンドを使用します。

    kubectl describe httproute
    

    カスタム リクエストとレスポンス ヘッダーを構成する

    カスタム リクエスト ヘッダーとカスタム レスポンス ヘッダーを使用すると、HTTP(S) のリクエストとレスポンスに追加のヘッダーを指定できます。ロードバランサで検出された情報に応じて、これらのヘッダーには次の情報が含まれます。

    • クライアントまでのレイテンシ
    • クライアントの IP アドレスの地理的位置
    • TLS 接続のパラメータ

    デフォルトでは、バックエンド サービスとの間で送受信されるリクエストに追加されるカスタム ヘッダーはありません。HTTPRoute のフィルタを使用して、カスタム ヘッダーを明示的に構成する必要があります。

    カスタム ヘッダーを構成するには、次のように HTTPRoute のルールにフィルタ セクションを追加します。

    カスタム リクエスト ヘッダーを構成する

    RequestHeaderModifier フィルタを含む HTTPRoute マニフェストを作成し、http-route-request.yaml: として保存します。

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: HTTPRoute
      metadata:
        name: store
      spec:
        <...>
        rules:
            filters:
              - type: RequestHeaderModifier
                requestHeaderModifier:
                  <...>
    

    次のようにマニフェストを適用します。

      kubectl apply -f http-route-request.yaml
    

    カスタム レスポンス ヘッダーを構成する

    ResponseHeaderModifier フィルタを含む HTTPRoute マニフェストを作成し、http-route-response.yaml: として保存します。

    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: store
    spec:
      <...>
      rules:
          filters:
            - type: ResponseHeaderModifier
              responseHeaderModifier:
                <...>
    

    次のようにマニフェストを適用します。

      kubectl apply -f http-route-response.yaml
    

    Gateway API の実装に説明されているように、ヘッダーの追加、設定、削除を行うことができます。Google Cloud でサポートされている変数を使用して、カスタム ヘッダーで HTTPRoute を構成できます。

    例 1:

    バックエンド サービスに送信する前にクライアントの位置情報を HTTP リクエストに追加する HTTPRoute を構成するには、HTTPRoute マニフェストを作成して external-http-request.yaml という名前を付けます。

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: HTTPRoute
      metadata:
        name: store
      spec:
        parentRefs:
          - kind: Gateway
            name: external-http
        hostnames:
        - store.example.com
        rules:
          - matches:
            - path:
                type: PathPrefix
                value: /fr
            filters:
              - type: RequestHeaderModifier
                requestHeaderModifier:
                  add:
                    - name: X-Client-Geo-Location
                      value: "{client_region},{client_city}"
            backendRefs:
              - name: store-french
                port: 8080
    

    たとえば、フランスのストラスブールにあるクライアントの場合、Gateway は X-Client-Geo-Location:FR,Strasbourg としてヘッダーを追加します。

    例 2:

    HTTP Strict Transport Security をサポートするカスタム レスポンス ヘッダーを追加する HTTPRoute を構成するには、HTTPRoute マニフェストを作成して external-http-response.yaml という名前を付けます。

      apiVersion: gateway.networking.k8s.io/v1beta1
      kind: HTTPRoute
      metadata:
        name: store
      spec:
        parentRefs:
          - kind: Gateway
            name: external-http
        hostnames:
        - store.example.com
        rules:
          - matches:
            - path:
                type: PathPrefix
                value: /de
            filters:
              - type: ResponseHeaderModifier
                responseHeaderModifier:
                  add:
                    - name: Strict-Transport-Security
                      value: max-age=63072000
            backendRefs:
              - name: store-german
                port: 8080
    

    構成を確認する

    1. カスタム リクエスト ヘッダーとカスタム レスポンス ヘッダーを構成した後に構成を確認するには、次の操作を行います。

        kubectl get httproute
      

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

        NAME    HOSTNAMES               AGE
        store   ["store.example.com"]   4d23h
      
    2. 詳細を確認するには、describe コマンドを使用します。

        kubectl describe httproute
      

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

        Name:         store
        Namespace:    default
        Labels:       <none>
        Annotations:  <none>
        API Version:  gateway.networking.k8s.io/v1beta1
        Kind:         HTTPRoute
        Metadata:
          Creation Timestamp:  2023-05-27T00:51:01Z
          Generation:          5
          Resource Version:    25418887
          UID:                 2e07a1b8-420b-41b4-acd1-cecbfcd39f42
        Spec:
          Hostnames:
            store.example.com
          Parent Refs:
            Group:  gateway.networking.k8s.io
            Kind:   Gateway
            Name:   external-http
          Rules:
            Backend Refs:
              Group:
              Kind:    Service
              Name:    store-v1
              Port:    8080
              Weight:  1
            Matches:
              Path:
                Type:   PathPrefix
                Value:  /
            Backend Refs:
              Group:
              Kind:    Service
              Name:    store-v2
              Port:    8080
              Weight:  1
            Matches:
              Headers:
                Name:   env
                Type:   Exact
                Value:  canary
              Path:
                Type:   PathPrefix
                Value:  /
            Backend Refs:
              Group:
              Kind:    Service
              Name:    store-german
              Port:    8080
              Weight:  1
            Filters:
              Request Header Modifier:
                Add:
                  Name:   X-Client-Geo-Location
                  Value:  {client_region},{client_city}
              Type:       RequestHeaderModifier
            Matches:
              Path:
                Type:   PathPrefix
                Value:  /de
        Status:
          <...>
      

    ルートのステータス

    HTTPRoute リソースは条件とイベントを出力します。これにより、HTTPRoute が 1 つ以上の Gateway と正常にバインドされたかどうか、または拒否されたかどうかを確認できます。

    HTTPRoute 条件

    HTTPRoute 条件は、Route とバインドされている Gateway のステータスを示します。1 つの Route は複数の Gateway にバインドできるため、これは、Gateway および Route と Gateway 間の個々の条件のリストとなります。

    • Accepted=True は、HTTPRoute が Gateway に正常にバインドされたことを示します。
    • Accepted=False は、HTTPRoute がこの Gateway とのバインディングで拒否されたことを示します。

    Gateway bindings 見出しに「Gateway」がない場合、HTTPRoute ラベルと Gateway ラベルセレクタが一致していない可能性場合があります。これは、どの Gateway も Route を選択していない場合に発生します。

    HTTPRoute イベント

    HTTPRoute イベントは、HTTPRoute のステータスの詳細を提供します。イベントは、次の理由でグループ化されます。

    • ADD イベントは、リソースの追加によってトリガーされます。
    • UPDATE イベントは、リソースの更新によってトリガーされます。
    • SYNC イベントは、定期的な調整でトリガーされます。

    ルートのマージ、優先度、検証

    ルートの優先度

    Gateway API は、厳密な優先ルールを定義し、ルーティング ルールが重複している Route がトラフィックを照合する方法を制御します。重複する 2 つの HTTPRoutes 間の優先度は次のとおりです。

    1. ホスト名のマージ: 最も長い、または最も具体的なホスト名と一致。
    2. パスのマージ: 最も長い、または最も具体的なパスと一致。
    3. ヘッダーのマージ: 一致する HTTP ヘッダーの最大数。
    4. 競合: 前述の 3 つのルールが優先されない場合、最も古いタイムスタンプの HTTPRoute リソースが使用されます。

    ルートのマージ

    gke-l7 GatewayClasses の場合、特定の Gateway のすべての HTTPRoute は同じ URL マップリソースにマージされます。HTTPRoute をマージする方法は、HTTPRoute 間の重複のタイプによって異なります。前述の例の HTTPRoute は、ルートのマージと優先順位を示す 3 つの HTTPRoute に分割できます。

    1. ルートのマージ: 3 つの HTTPRoute はすべて同じ internal-http Gateway に接続されるため、1 つにマージされます。
    2. ホスト名のマージ: store.example.com の 3 つの Route がすべて一致するため、ホスト名ルールがマージされます。
    3. パスのマージ: store-german-route はより具体的なパス /de を持つため、マージされません。store-v1-route と store-v2-route はどちらも同じ /* パスと一致するため、これらのパスでマージされます。
    4. ヘッダーのマージ: store-v2-route には、store-v1-route よりも具体的な一連の HTTP ヘッダーの一致があるため、マージされません。
    5. 競合: Route をホスト名、パス、ヘッダーとマージできるため、競合は発生せず、すべてのルーティング ルールがトラフィックに適用されます。

    前述の例で使用した 1 つの HTTPRoute は、これらの 3 つのルートと同等です。

    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-v1-route
    spec:
      parentRefs:
      - kind: Gateway
        name: internal-http
      hostnames:
      - "store.example.com"
      rules:
      - backendRefs:
        - kind: Service
          name: store-v1
          port: 8080
    ---
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-v2-route
    spec:
      parentRefs:
      - kind: Gateway
        name: internal-http
      hostnames:
      - "store.example.com"
      rules:
      - matches:
        - headers:
          - type: Exact
            name: env
            value: canary
        backendRefs:
        - kind: Service
          name: store-v2
          port: 8080
    ---
    kind: HTTPRoute
    apiVersion: gateway.networking.k8s.io/v1beta1
    metadata:
      name: store-german-route
    spec:
      parentRefs:
      - kind: Gateway
        name: internal-http
      hostnames:
      - "store.example.com"
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /de
        backendRefs:
        - kind: Service
          name: store-german
          port: 8080
    

    Kubernetes Gateway と Istio Gateway

    Kubernetes Gateway API と Istio API にはどちらも Gateway という名前のリソースがあります。機能は似ていますが、同じリソースではありません。同じ Kubernetes クラスタで Istio と Gateway API を使用している場合、コマンドラインで kubectl を使用するときに名前の重複が発生します。kubectl get gateway は Kubernetes Gateway リソースを返す場合がありますが、Istio Gateway リソースは返しません。その逆も同様です。

    $ kubectl api-resources
    NAME       SHORTNAMES   APIGROUP                       NAMESPACED   KIND
    gateways   gw           networking.istio.io/v1beta1    true         Gateway
    gateways   gtw          networking.k8s.io/v1beta1      true         Gateway
    

    Istio を使用して GKE 1.20 以降にアップグレードする場合は、Gateway リソースの省略名を使用するか、API グループを指定することをおすすめします。Kubernetes Gateway の省略名は gtw、Istio ゲートウェイの省略名は gw です。次のコマンドは、Kubernetes Gateway リソースと Istio Gateway リソースをそれぞれ返します。

    # Kubernetes Gateway
    $ kubectl get gtw
    NAME                        CLASS
    multi-cluster-gateway       gke-l7-global-external-managed-mc
    
    $ kubectl get gateway.networking.x-k8s.io
    NAME                        CLASS
    multi-cluster-gateway       gke-l7-global-external-managed-mc
    
    # Istio Gateway
    $ kubectl get gw
    NAME               AGE
    bookinfo-gateway   64m
    
    $ kubectl get gateway.networking.istio.io
    NAME               AGE
    bookinfo-gateway   64m
    

    トラブルシューティング

    リージョンにプロキシ専用サブネットが存在しない

    症状:

    リージョン Gateway(内部または外部)を作成する際に、次の問題が発生する場合があります。

    generic::invalid_argument: error ensuring load balancer: Insert: Invalid value for field 'resource.target': 'regions/[REGION_NAME]/targetHttpProxies/gkegw-x5vt-default-internal-http-[ID]'. A reserved managed proxy subnetwork with purpose REGIONAL_MANAGED_PROXY is required.
    

    理由:

    このエラー メッセージは、Gateway のリージョンにプロキシ専用サブネットが存在しないことを示します。

    回避策:

    この問題を解決するには、プロキシ専用サブネットを構成します。

    プロキシ専用サブネットが誤った目的でリージョンにすでに存在する

    症状:

    リージョン Gateway(内部または外部)にプロキシ専用サブネットを作成する際に、次の問題が発生する場合があります。

    ERROR: (gcloud.compute.networks.subnets.create) Could not fetch resource:
     - The resource 'projects/[PROJECT_NAME]/regions/[REGION_NAME]/subnetworks/[PROXY_ONLY_SUBNET_NAME]' already exists
    

    理由:

    このエラー メッセージは、すでにプロキシ専用サブネットが存在するリージョンにリージョン プロキシ専用サブネットを作成しようとしたことを示します。

    回避策:

    この問題を解決する手順は次のとおりです。

    1. リージョンにプロキシ専用サブネットがすでに存在することを確認し、目的が正しいことを確認します。

      1. サブネットを一覧表示して、リージョン内のプロキシ専用サブネットを見つけます。

        gcloud compute networks subnets list --regions=COMPUTE_REGION
        

        COMPUTE_REGION は、リージョン Gateway を作成する Compute Engine リージョンに置き換えます。

      2. リージョン内のプロキシ専用サブネットの説明を取得して、目的を確認します。

        gcloud compute networks subnets describe PROXY_ONLY_SUBNET \
            --region COMPUTE_REGION | grep -E 'name|purpose'
        

        PROXY_ONLY_SUBNET は、プロキシ専用サブネットに置き換えます。

      GKE Gateway は、リージョン Gateway(内部またはリージョン)の REGIONAL_MANAGED_PROXY プロキシ専用サブネットのみをサポートします。

    2. リージョン内の既存のプロキシ専用サブネットが INTERNAL_HTTPS_LOAD_BALANCER の目的で作成された場合は、サブネットの目的を REGIONAL_MANAGED_PROXY に移行します。

    次のステップ