HTTP(S) 負荷分散用 GKE Ingress

このページでは、HTTP(S) 負荷分散で Ingress がどのように機能するかについて概要を説明します。Google Kubernetes Engine(GKE)では、GKE Ingress と呼ばれる、組み込みのマネージド Ingress コントローラを使用できます。このコントローラは、GKE で HTTP(S) ワークロードを処理する Google Cloud ロードバランサとして Ingress リソースを実装します。

概要

GKE では、Ingress オブジェクトが、クラスタ内で実行されるアプリケーションに HTTP(S) トラフィックをルーティングするルールを定義します。1 つの Ingress オブジェクトは 1 つ以上の Service オブジェクトに関連付けられており、それぞれの Service オブジェクトは Pod のセットに関連付けられています。

Ingress オブジェクトを作成すると、GKE Ingress コントローラによって Google Cloud HTTP(S) ロードバランサが作成され、Ingress および関連する Service の情報に従って構成されます。

外部および内部トラフィック用 Ingress

GKE Ingress リソースには次の 2 種類があります。

HTTP(S) 負荷分散の特長

Ingress により構成された HTTP(S) 負荷分散には、次のような特長があります。

柔軟な Service の構成
Ingress では、トラフィックがどのように Service に到達し、そのトラフィックがどのようにアプリケーションにルーティングされるかを定義します。また、クラスタ内の複数の Service に対して単一の IP アドレスを割り当てることができます。
Google Cloud ネットワーク サービスとの統合
Ingress では、Google マネージド SSL 証明書(ベータ版)Google Cloud ArmorCloud CDNIdentity-Aware Proxy などの Google Cloud 機能を構成できます。
複数の TLS 証明書のサポート
Ingress では、リクエストの終了に際して複数の TLS 証明書を使用するよう指定できます。

コンテナ ネイティブの負荷分散

コンテナ ネイティブの負荷分散とは、ネットワーク エンドポイント グループ(NEG)を使用して GKE 内の Pod エンドポイントに直接負荷を分散する手法のことです。

NEG が使用されるようになる前は、Compute Engine ロードバランサがノード IP をバックエンドとして使用して、インスタンス グループにトラフィックを送信していました。この方法には次のいくつかの制限が課されます。

  • 2 ホップの負荷分散になります。
  • レイテンシが増えます。
  • Compute Engine ロードバランサには Pod が直接見えないため、トラフィックの負荷分散は最適なものにはなりません。

NEG を使用する場合、トラフィックはノード IP または kube-proxy ネットワーキングを移動するのではなく、Ingress プロキシから直接 Pod IP に負荷分散されます。さらに、Kubernetes の readiness / liveness チェックだけでなく、負荷分散の観点からも Pod の健全性を判断するために、Pod の readiness ゲートが実装されます。これにより、Pod の起動、Pod やノードの損失などのライフサイクル イベントでトラフィックが破棄されることを防げます。

コンテナ ネイティブの負荷分散を活用するには、NEG を使用して Ingress をデプロイすることを強くおすすめします。可能な場合は常に、この方法を使用してください。これは Services のデフォルト モードではないため、Ingress ルールのバックエンドとされている Service に cloud.google.com/neg アノテーションを設定して明示的に適用する必要があります。

kind: Service
    ...
      annotations:
        cloud.google.com/neg: '{"ingress": true}'
    ...
    

複数のバックエンド サービス

HTTP(S) ロードバランサにより、単一の固定 IP アドレスを使用して、さまざまなバックエンド サービスにリクエストをルーティングできます。

たとえば、URL パスに応じてリクエストを異なるバックエンド サービスにルーティングするようにロードバランサを構成できます。たとえば、your-store.example に送信されたリクエストは、正価の商品を表示するバックエンド サービスにルーティングされ、your-store-example/discounted に送信されたリクエストは、値引き対象商品を表示するバックエンド サービスにルーティングされるようにできます。

ホスト名に応じてリクエストをルーティングするように、ロードバランサを構成することもできます。たとえば、your-store.example に送信されたリクエストはあるバックエンド サービスに送信され、your-experimental-store.example に送信されたリクエストは別のバックエンド サービスに送信されるようにできます。

GKE クラスタで、HTTP(S) ロードバランサを作成して構成するには、Kubernetes Ingress オブジェクトを作成します。1 つの Ingress オブジェクトは、1 つ以上の Service オブジェクトに関連付けられている必要があります。それぞれの Service オブジェクトは、Pod のセットに関連付けられています。

my-ingress という名前の Ingress のマニフェストを次に示します。

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: my-ingress
    spec:
      rules:
      - http:
          paths:
          - path: /*
            backend:
              serviceName: my-products
              servicePort: 60000
          - path: /discounted
            backend:
              serviceName: my-discounted-products
              servicePort: 80
    

Ingress を作成すると、GKE Ingress コントローラにより、Ingress および関連する Service の情報に従って HTTP(S) ロードバランサの作成と構成が行われます。また、ロードバランサには固定 IP アドレスが割り当てられます。この IP アドレスは、ドメイン名に関連付けることができます。

上記の例で、ロードバランサの IP アドレスをドメイン名 your-store.example に関連付けたと仮定します。クライアントが your-store.example にリクエストを送信すると、そのリクエストはポート 60000 の my-products という名前の Kubernetes Service にルーティングされます。クライアントが your-store.example/discounted にリクエストを送信すると、そのリクエストはポート 80 の my-discounted-products という名前の Kubernetes Service にルーティングされます。

Ingress の path フィールドでサポートされているワイルドカード文字は「*」のみです。「*」はスラッシュ(「/」)の直後に置かれる必要があり、パターンの最後の文字でなければなりません。たとえば、/*/foo/*/foo/bar/* は有効なパターンですが、*、/foo/bar*、/foo/*/bar は有効ではありません。

より具体的なパターンのほうが、そうでないものよりも優先されます。/foo/*/foo/bar/* の両方を使用すると、/foo/bar/bat/foo/bar/* と比較されます。

パスの制限とパターン マッチングの詳細については、URL マップのドキュメントをご覧ください。

my-products Service のマニフェストは次のようになります。

    apiVersion: v1
    kind: Service
    metadata:
      name: my-products
    spec:
      type: NodePort
      selector:
        app: products
        department: sales
      ports:
      - protocol: TCP
        port: 60000
        targetPort: 50000
    

この Service マニフェストでは、typeNodePort になっていることに注意してください。HTTP(S) ロードバランサの構成に使用する Ingress については、このタイプにする必要があります。

Service マニフェストの selector フィールドでは、app: products ラベルと department: sales ラベルの両方が設定された Pod がこの Service のメンバーであると示しています。

リクエストがポート 60000 で Service に到達すると、そのリクエストは TCP ポート 50000 のメンバー Pod の 1 つにルーティングされます。

メンバー Pod ごとに、TCP ポート 50000 でリッスンするコンテナが必要です。

my-discounted-products Service のマニフェストは次のようになります。

    apiVersion: v1
    kind: Service
    metadata:
      name: my-discounted-products
    spec:
      type: NodePort
      selector:
        app: discounted-products
        department: sales
      ports:
      - protocol: TCP
        port: 80
        targetPort: 8080
    

Service マニフェストの selector フィールドでは、app: discounted-products ラベルと department: sales ラベルの両方が設定された Pod がこの Service のメンバーであると示しています。

リクエストがポート 80 で Service に到達すると、そのリクエストは TCP ポート 8080 の 1 つのメンバーポッドにルーティングされます。

メンバー Pod ごとに、TCP ポート 8080 でリッスンするコンテナが必要です。

デフォルトのバックエンド

デフォルトのバックエンドを指定するには、Ingress マニフェストに backend フィールドを指定します。rules フィールドのパスと一致しないリクエストはすべて、backend フィールドで指定された Service とポートに送信されます。たとえば、次の Ingress では、/ または /discounted と一致しないリクエストが my-products という名前の Service ポート 60001 に送信されます。

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: my-ingress
    spec:
      backend:
        serviceName: my-products
        servicePort: 60001
      rules:
      - http:
          paths:
          - path: /
            backend:
              serviceName: my-products
              servicePort: 60000
          - path: /discounted
            backend:
              serviceName: my-discounted-products
              servicePort: 80
    

デフォルトのバックエンドを指定しない場合、GKE は 404 を返すバックエンドをデフォルトにします。

Ingress と Compute Engine リソースのマッピング

GKE Ingress コントローラは、クラスタにデプロイされている Ingress リソースに基づいて、Compute Engine ロードバランサ リソースをデプロイして管理します。Compute Engine リソースのマッピングは、Ingress リソースの構造によって異なります。これらのリソースのマッピングを把握しておくと、計画、設計、トラブルシューティングに役立ちます。

複数のバックエンド サービスのセクションに記載されている my-ingress マニフェストでは、2 つの異なる Kubernetes Services を参照する 2 つの URL パスと一致する外部 Ingress リソースを指定しています。my-ingress の代わりとして作成される Compute Engine リソースには次のものがあります。

  • forwardingRule に対応する公開 VIP。
  • ヘルスチェックのトラフィックとアプリケーションのトラフィックを許可する Compute Engine ファイアウォール ルール。
  • ターゲット HTTP プロキシ。TLS が構成されている場合は、HTTPS プロキシが追加されます。
  • 単一の hostRule として /* と /discounted の pathMatcher を設定した URL マップ。これは、対応する backendService を指します。
  • 各 Service の Pod IP のリストをエンドポイントとする NEG。これらは my-discounted-products および my-products Service の結果として作成されます。次の図に、Ingress と Compute Engine リソースのマッピングの概要を示します。

Ingress と Compute Engine リソースのマッピングを示す図

SSL 証明書を提供するためのオプション

HTTPS ロードバランサに SSL 証明書を提供する方法は 3 つあります。

Google マネージド証明書
Google マネージド SSL 証明書は、ドメインに対してプロビジョニング、デプロイ、更新、管理されます。マネージド証明書はワイルドカード ドメインをサポートしません。
Google Cloud と共有されるセルフマネージド証明書
独自の SSL 証明書をプロビジョニングして、Google Cloud プロジェクトで証明書リソースを作成できます。その後、証明書リソースを Ingress のアノテーションでリストして、証明書を使用する HTTP(S) ロードバランサを作成できます。詳しくは、事前共有証明書に関する説明をご覧ください。
Secret リソースとしてのセルフマネージド証明書
自身の SSL 証明書をプロビジョニングして、それを保持するための Secret を作成できます。その Secret を Ingress 仕様で参照して、この証明書を使用する HTTP(S) ロードバランサを作成できます。詳細については、Secret で証明書を使用する際の手順をご覧ください。

ヘルスチェック

Ingress を通して公開される Service は、ロードバランサからのヘルスチェックに応答する必要があります。負荷分散されたトラフィックの最終的な送信先であるコンテナは、正常であることを示すために次のいずれかの操作を行います。

  • / パスに対する GET リクエストに対し、HTTP 200 ステータスのレスポンスを返す。

  • HTTP 準備プローブを構成する。準備プローブで指定された path に対する GET リクエストに対し、HTTP 200 ステータスのレスポンスを返す。Ingress を通じて公開される Service は、準備プローブが有効になっているコンテナポートと同じコンテナポートを指す必要があります。

    たとえば、コンテナが次のようにこの準備プローブを指定したとします。

    ...
        readinessProbe:
          httpGet:
            path: /healthy
        

    この場合、コンテナの /healthy パスに対応するハンドラが HTTP 200 ステータスを返せば、ロードバランサはコンテナが正常に動作していると見なします。

複数の TLS 証明書の使用

HTTP(S) ロードバランサで、your-store.example および your-experimental-store.example という名前の 2 つのホストからコンテンツを提供するとします。ここで、ロードバランサは、your-store.example 用と experimental-store.example 用で異なる証明書を使用するものとします。

これを行うには、Ingress マニフェストで複数の証明書を指定します。ロードバランサは、指定された証明書のうち、リクエストで使用されているホスト名と一致する共通名(CN)が含まれている証明書を選択します。複数の証明書を構成する方法について詳しくは、Ingress での HTTP(S) 負荷分散のための複数の SSL 証明書の使用をご覧ください。

Kubernetes Service と Google Cloud バックエンド サービスの比較

Kubernetes ServiceGoogle Cloud バックエンド サービスは別物です。両者の間には強い関係がありますが、その関係は必ずしも 1 対 1 ではありません。GKE Ingress コントローラは、Ingress マニフェスト内の各(serviceNameservicePort)ペア用に 1 つの Google Cloud バックエンド サービスを作成します。したがって、1 つの Kubernetes Service オブジェクトが複数の Google Cloud バックエンド サービスに関係する可能性があります。

制限事項

  • Ingress の名前空間と名前の長さの合計は 40 文字以内にする必要があります。このガイドラインに従わないと、GKE Ingress コントローラが正常に動作しない可能性があります。詳細については、GitHub でこの問題をご覧ください。

  • URL マップの最大ルール数は 50 です。つまり、Ingress には最大 50 のルールを指定できます。

  • GKE Ingress コントローラで NEG を使用しない場合、GKE クラスタのノード数は 1,000 に制限されます。NEG を使用して Service をデプロイする場合、GKE のノード数に課される制限はありません。Ingress で公開されている、NEG を使用しない Service は、1,000 ノードを超えるクラスタでは正しく機能しません。

  • GKE Ingress コントローラで readinessProbes をヘルスチェックとして使用するには、Ingress の作成時に Ingress 用の Pod が存在している必要があります。レプリカ数が 0 にスケールされている場合は、デフォルトのヘルスチェックが適用されます。詳細については、こちらの問題のコメントをご覧ください。

  • Ingress の作成後に Pod の readinessProbe を変更しても、Ingress には影響を与えません。

  • クライアントとロードバランサの間のレイテンシを最小限に抑える目的で、HTTPS ロードバランサは、グローバルに分散するロケーションで TLS を終端します。TLS の終端を指定する必要がある場合は、カスタム ingress コントローラと GCP ネットワーク負荷分散を使用し、適切なリージョンにあるバックエンドで TLS を終端させてください。

次のステップ