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 コントローラによって 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 クラスタでは、Kubernetes Ingress オブジェクトを作成して HTTP(S) ロードバランサの作成と構成を行います。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 アドレスをドメイン名 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 ラベルの両方を持つポッドがこの Service のメンバーであることを示しています。

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

メンバーポッドごとに、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 ラベルの両方を持つポッドがこの Service のメンバーであることを示しています。

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

メンバーポッドごとに、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 を作成できます。そして、Ingress 仕様の Secret を参照して、証明書を使用する 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 を終端させてください。

次のステップ