Ingress を使用した HTTP(S) 負荷分散

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

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

HTTP(S) 負荷分散の特長

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

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

ここに挙げた特長の詳細については、HTTP(S) 負荷分散のコンセプトをご覧ください。

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

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

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

制限事項

Ingress の名前空間と名前の長さの合計は 55 文字以内にする必要があります。このガイドラインに従わないと、GKE Ingress コントローラが異常動作する恐れがあります。詳細については、こちらの問題をご覧ください。

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

GKE Ingress コントローラを使用する場合、クラスタに 1,000 を超えるノードを含めることはできません。

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

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

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

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 オブジェクトは、ポッドのセットに関連付けられています。

Ingress のマニフェストを次に示します。

apiVersion: extensions/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 のメンバーポッドにルーティングされます。

ここで、各メンバーポッドには、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 のメンバーポッドにルーティングされます。

ここで、各メンバーポッドには、TCP ポート 8080 でリッスンするコンテナが必要です。

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

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

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

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

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

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

    ...
    readinessProbe:
      httpGet:
        path: /healthy
    

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

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

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

GCP 機能のサポート

BackendConfig を使用して、Cloud ArmorCloud CDNCloud IAP などの機能を利用できるように HTTP(S) ロードバランサを構成できます。

BackendConfig は、GCP 機能の構成情報を保持するカスタム リソースです。

Ingress マニフェストが Service を参照し、その Service マニフェストが beta.cloud.google.com/backend-config アノテーションを使用して BackendConfig を参照します。

...
kind: Ingress
...
spec:
  rules:
  - http:
      paths:
      - path: /
        backend:
          serviceName: my-service
          servicePort: 80
...

kind: Service
metadata:
  name: my-service
  ...
  annotations:
    beta.cloud.google.com/backend-config: '{"ports": {"80":"my-backend-config"}}'
spec:
  type: NodePort
  ...
 

WebSocket のサポート

HTTP(S) 負荷分散では、WebSocket プロトコルはそのままで機能します。構成は不要です。

WebSocket プロトコルを使用する場合は、デフォルトの 30 秒よりも長いタイムアウト値を使用することをおすすめします。Ingress で構成されたバックエンド サービスのタイムアウト値を設定するには、BackendConfig オブジェクトを作成し、Service マニフェストで beta.cloud.google.com/backend-config アノテーションを使用します。

詳しくは、Ingress によるバックエンド サービスの構成をご覧ください。

HTTP(S) ロードバランサの静的 IP アドレス

Ingress オブジェクトを作成すると、クライアントが Service、さらには実行中のコンテナにアクセスするために使用できる外部の固定 IP アドレスを取得できます。この IP アドレスは、Ingress オブジェクトの存続期間にわたって持続するという意味で固定されます。ただし、Ingress を削除して同じマニフェスト ファイルから新しい Ingress を作成しても、同じ外部 IP アドレスが得られる保証はありません。

Ingress を削除して新たに作成しても、同じ IP アドレスを維持したい場合には、グローバル静的外部 IP アドレスを予約する必要があります。その後、Ingress マニフェストに、予約した静的 IP アドレスの名前を示すアノテーションを追加します。

たとえば、my-static-address という名前のグローバル静的外部 IP アドレスを予約した場合は、Ingress マニフェストに、次のように kubernetes.io/ingress.global-static-ip-name アノテーションを追加します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    kubernetes.io/ingress.global-static-ip-name: my-static-address

Ingress の静的外部 IP アドレスの作成方法については、静的 IP アドレスの構成および静的 IP アドレスを使用したドメイン名の構成をご覧ください。

クライアントとロードバランサ間の HTTPS(TLS)の設定

HTTP(S) ロードバランサは、クライアントとアプリケーションの間のプロキシとして機能します。クライアントからの HTTPS リクエストを受け入れるには、ロードバランサは証明書を持っていなければなりません。これにより、適切な送信先であることをクライアントに示すことができます。さらに、ロードバランサには、HTTPS handshake を完了するための秘密鍵も必要です。

ロードバランサがクライアントからの HTTPS リクエストを受け入れると、クライアントとロードバランサ間のトラフィックは TLS で暗号化されます。ただし、TLS 暗号化はロードバランサで終了し、アプリケーションへのリクエストの転送は暗号化なしに行われます。ロードバランサとアプリケーションの間でトラフィックを暗号化する方法については、ロードバランサとアプリケーション間の HTTPS をご覧ください。

Google マネージド SSL 証明書(ベータ版)を使用するか、自分で管理している証明書を使用するか選択できます。Google マネージド証明書を使用する Ingress の作成について詳しくは、Google マネージド SSL 証明書(ベータ版)の使用をご覧ください。

自身で作成した証明書とキーを HTTP(S) ロードバランサで利用するために、Ingress マニフェストの tls フィールドに Kubernetes Secret の名前を指定できます。以前に作成した Secret には、証明書とキーが保持されています。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress-2
spec:
  tls:
  - secretName: my-secret
  rules:
  - http:
      paths:
      - path: /*
        backend:
          serviceName: my-metrics
          servicePort: 60000

Secret への変更は定期的に拾われるため、Secret 内のデータを変更した場合、それらの変更がロードバランサに適用されるまでに最大 10 分かかります。

Secret を使用してロードバランサに証明書を提供する方法については、Ingress を使用した HTTP(S) 負荷分散における複数 SSL 証明書の使用をご覧ください。

HTTP の無効化

クライアントと HTTP(S) ロードバランサ間のすべてのトラフィックで HTTPS を使用する場合は、Ingress のマニフェストに kubernetes.io/ingress.allow-http を含めることで HTTP を無効にできます。アノテーションの値を "false" に設定します。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress-2
  annotations:
    kubernetes.io/ingress.allow-http: "false"
spec:
  tls:
  - secretName: my-secret
  ...

ロードバランサの事前共有証明書

HTTP(S) を終端させるために、Kubernetes Secret を使用してロードバランサに証明書を提供する代わりに、事前に GCP プロジェクトにアップロードしておいた証明書を使用することもできます。詳細については、事前共有証明書の使用および Ingress を使用した HTTP(S) 負荷分散における複数 SSL 証明書の使用をご覧ください。

ロードバランサとアプリケーション間の HTTPS(TLS)

HTTP(S) ロードバランサは、クライアントとアプリケーションの間のプロキシとして機能します。クライアントは、HTTP または HTTPS を使用してロードバランサ プロキシと通信できます。ただし、ロードバランサ プロキシからアプリケーションへの接続には、デフォルトで HTTP を使用します。GKE ポッドで実行しているアプリケーションが HTTPS リクエストを受信できる場合は、ロードバランサがリクエストをアプリケーションに転送するときに HTTPS を使用するようにロードバランサを構成します。

ロードバランサとアプリケーションの間で使用されるプロトコルを構成するには、cloud.google.com/app-protocols アノテーションを Service マニフェストで使用します。

次の Service マニフェストでは、2 つのポートを指定しています。そのアノテーションによると、HTTP(S) ロードバランサが Service のポート 80 をターゲットにしているとき、HTTP を使用する必要があります。また、ロードバランサが Service のポート 443 をターゲットにしているとき、HTTPS を使用する必要があります。

apiVersion: v1
kind: Service
metadata:
  name: my-service-3
  annotations:
    cloud.google.com/app-protocols: '{"my-https-port":"HTTPS","my-http-port":"HTTP"}'
spec:
  type: NodePort
  selector:
    app: metrics
    department: sales
  ports:
  - name: my-https-port
    port: 443
    targetPort: 8443
  - name: my-http-port
    port: 80
    targetPort: 50001

cloud.google.com/app-protocols アノテーションは、古い service.alpha.kubernetes.io/app-protocols アノテーションと同じ目的で用いられます。古いアノテーション名と新しいアノテーション名は、次の Service マニフェストに示すように、共存できます。両方のアノテーションが同じ Service マニフェストに出現する場合は、service.alpha.kubernetes.io/app-protocols が優先されます。

apiVersion: v1
kind: Service
metadata:
  name: my-service-3
  annotations:
    cloud.google.com/app-protocols: '{"my-https-port":"HTTPS","my-http-port":"HTTP"}'
    service.alpha.kubernetes.io/app-protocols: '{"my-first-port":"HTTPS","my-second-port":"HTTP"}'
spec:
  type: NodePort
  selector:
    app: metrics
    department: sales
  ports:
  - name: my-first-port
    port: 443
    targetPort: 8443
  - name: my-second-port
    port: 80
    targetPort: 50001

複数の TLS 証明書の使用

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

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

次のステップ

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Kubernetes Engine のドキュメント