コンテナ ネイティブの負荷分散を使用する

このページでは、Google Kubernetes Engine でコンテナ ネイティブの負荷分散を使用する方法について説明します。

概要

コンテナ ネイティブの負荷分散により、HTTP(S) ロードバランサはポッドを直接ターゲットにすることができ、またトラフィックをポッドに均等に分配できます。

コンテナ ネイティブの負荷分散では、ネットワーク エンドポイント グループ(NEG)というデータモデルが利用されます。これは、IP とポートのペアで示されるネットワーク エンドポイントのコレクションです。

利点

コンテナ ネイティブの負荷分散には以下の利点があります。

ポッドは負荷分散の最高レベルの構成要素
kube-proxy によってノードの iptables ルールが構成され、トラフィックがポッドに配信されます。コンテナ ネイティブの負荷分散を使用しない場合、ロードバランサのトラフィックはノード インスタンス グループに送られ、iptables ルールを介してポッドにルーティングされます。しかし、このポッドは同じノードにあるとは限りません。コンテナ ネイティブの負荷分散を使用すると、ロードバランサのトラフィックは受信に適したポッドに直接配信され、余分なネットワーク ホップがなくなります。また、コンテナ ネイティブの負荷分散ではポッドを直接ターゲットとするため、ヘルスチェックもしやすくなります。

デフォルトの動作(左)とコンテナ ネイティブの負荷分散の動作を比較した図
ネットワーク パフォーマンスの改善
コンテナ ネイティブのロードバランサはポッドと直接通信を行います。これにより接続でのネットワーク ホップが減少するため、レイテンシとスループットの両方が改善されます。
可視性の向上
コンテナ ネイティブの負荷分散を使用すると、Stackdriver UI のサポートを含む、クライアントから HTTP(S) ロードバランサまでのラウンドトリップ時間(RTT)が可視化されます。これにより、NEG レベルでのサービスのトラブルシューティングが容易になります。
HTTP(S) 負荷分散機能のサポート
コンテナ ネイティブの負荷分散では、Google Cloud ArmorCloud CDNCloud Identity-Aware Proxy などの GCP サービスとの統合をはじめとするいくつかの HTTP(S) 負荷分散機能が Google Kubernetes Engine でネイティブ サポートされています。また、トラフィックを正確に分配するための負荷分散アルゴリズムも備えています。
Traffic Director のサポート
NEG データモデルが Traffic Director を使用するために必要な、GCP で提供される、フルマネージドのサービス メッシュ用トラフィック コントロール プレーンです。

ポッドの readiness(準備完了)

関連するポッドについて、対応する Ingress コントローラは、cloud.google.com/load-balancer-neg-ready タイプの readiness ゲートを管理します。Ingress コントローラは、NEG 内のすべてのエンドポイントの健全性を含む、ロードバランサのヘルスチェック ステータスをポーリングします。ロードバランサのヘルスチェック ステータスが、特定のポッドに対応するエンドポイントが正常であることを示す場合、Ingress コントローラはポッドの readiness ゲート値を True に設定します。各ノードで実行されている kubelet は、この readiness ゲート値と、定義されている場合はポッドの readiness プローブの両方を考慮して、ポッドの有効な準備完了状況を計算します。

コンテナ ネイティブの負荷分散の場合、ポッドの readiness ゲートは次の環境で自動的に有効になります。

  • v1.13.8 以降を実行している v1.13 GKE クラスタ
  • v1.14.4 以降を実行している v1.14 GKE クラスタ

readiness ゲートは、ローリング アップデートのレートを制御します。上記の GKE バージョンでは、readiness ゲートが自動的にポッドに追加されます。ローリング アップデートを開始すると、GKE で新しいポッドが作成され、新しいポッドごとのエンドポイントが NEG に追加されます。ロードバランサから見てエンドポイントが正常な場合、Ingress コントローラは readiness ゲートを True に設定します。したがって、GKE が古いポッドを削除する前に、新しく作成されたポッドは少なくとも readiness ゲートを通過する必要があります。これにより、ポッドの対応するエンドポイントにロードバランサのヘルスチェックを通過させ、バックエンド容量が維持されるようにします。

コンテナ イメージが不適切であるか、ロードバランサのヘルスチェックが正しく構成されていないため、ポッドの readiness ゲートが準備完了であることを示さない場合、ロードバランサは新しいポッドにトラフィックを転送しません。更新した Deployment をロールアウトする際にこのようなエラーが発生した場合、新しいポッドを作成しようとすると、そのポッドの readiness ゲートが True にならないことによりロールアウトが停滞します。この状況を検出して修正する方法については、トラブルシューティングをご覧ください。

コンテナ ネイティブの負荷分散と readiness ゲートを使用しなければ、GKE は、ポッドを準備完了としてマークする前に、ロードバランサのエンドポイントが正常かどうかを検出できません。以前の Kubernetes バージョンでは、遅延の期間(Deployment の仕様の minReadySeconds)を指定することで、ポッドを削除して置換するレートを指定していました。

要件

Google Kubernetes Engine 上でコンテナ ネイティブのロードバランサを使用するには、次の要件を満たす必要があります。

Google Kubernetes Engine v1.13.8 または v1.14.4

コンテナ ネイティブのロードバランサは通常、次の環境で使用できます。

  • v1.13.8 以降を実行している v1.13 GKE クラスタ
  • v1.14.4 以降を実行している v1.14 GKE クラスタ
VPC ネイティブ

コンテナ ネイティブの負荷分散を使用するには、クラスタが VPC ネイティブである必要があります。詳細については、エイリアス IP を使用した VPC ネイティブ クラスタの作成をご覧ください。

HTTP 負荷分散

コンテナ ネイティブの負荷分散を使用するには、クラスタで HTTP 負荷分散を有効にする必要があります。GKE クラスタの HTTP 負荷分散はデフォルトで有効になっています。無効にしないでください。

制限事項

コンテナ ネイティブのロードバランサは、レガシー ネットワークでは動作しません。

制限事項

コンテナ ネイティブのロードバランサでは、内部ロードバランサおよびネットワーク ロードバランサはサポートされません。

料金

このガイドに沿って作成した Ingress によってプロビジョニングされた HTTP(S) ロードバランサには料金が発生します。ロードバランサの料金情報については、Compute Engine の料金ページで負荷分散と転送ルールをご覧ください。

コンテナ ネイティブの負荷分散を使用する

以降のセクションでは、Google Kubernetes Engine でのコンテナ ネイティブの負荷分散の構成について説明します。

VPC ネイティブ クラスタを作成する

コンテナ ネイティブの負荷分散を使用するには、有効なエイリアス IP を使用したクラスタを作成する必要があります。

たとえば、次のコマンドではゾーン us-central1-a でサブネットワークが自動プロビジョニングされるクラスタ neg-demo-cluster が作成されます。

gcloud container clusters create neg-demo-cluster \
    --enable-ip-alias \
    --create-subnetwork="" \
    --network=default \
    --zone=us-central1-a

Deployment を作成する

次に、クラスタにワークロードをデプロイします。

次の Deployment のサンプル、neg-demo-app では、コンテナ化された HTTP サーバーの単一インスタンスが実行されます。ポッドの readiness フィードバックを使用するワークロードを使用することをおすすめします。GKE バージョンの要件の詳細については、上記のポッドの readiness(準備完了)をご覧ください。

ポッドの readiness フィードバックを使用する

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: neg-demo-app # Label for the Deployment
  name: neg-demo-app # Name of Deployment
spec:
  selector:
    matchLabels:
      run: neg-demo-app
  template: # Pod template
    metadata:
      labels:
        run: neg-demo-app # Labels Pods from this Deployment
    spec: # Pod specification; each Pod created by this Deployment has this specification
      containers:
      - image: k8s.gcr.io/serve_hostname:v1.4 # Application to run in Deployment's Pods
        name: hostname # Container name
  

ハードコードされた遅延を使用する

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: neg-demo-app # Label for the Deployment
  name: neg-demo-app # Name of Deployment
spec:
  minReadySeconds: 60 # Number of seconds to wait after a Pod is created and its status is Ready
  selector:
    matchLabels:
      run: neg-demo-app
  template: # Pod template
    metadata:
      labels:
        run: neg-demo-app # Labels Pods from this Deployment
    spec: # Pod specification; each Pod created by this Deployment has this specification
      containers:
      - image: k8s.gcr.io/serve_hostname:v1.4 # Application to run in Deployment's Pods
        name: hostname # Container name
      # Note: The following line is necessary only on clusters running GKE v1.11 and lower.
      # For details, see https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing#align_rollouts
      terminationGracePeriodSeconds: 60 # Number of seconds to wait for connections to terminate before shutting down Pods
  

この Deployment では、各コンテナで HTTP サーバーが実行されます。HTTP サーバーは、単にアプリケーション サーバーのホスト名(サーバーが実行されているポッドの名前)をレスポンスとして返します。

このマニフェストを neg-demo-app.yaml として保存し、次のコマンドを実行して Deployment を作成します。

kubectl apply -f neg-demo-app.yaml

コンテナ ネイティブのロードバランサのサービスを作成する

Deployment を作成したら、ポッドをサービスにグループ化する必要があります。

次のサンプルのサービス neg-demo-svc は、前のセクションで作成したサンプルの Deployment をターゲットにしています。

apiVersion: v1
kind: Service
metadata:
  name: neg-demo-svc # Name of Service
  annotations:
    cloud.google.com/neg: '{"ingress": true}' # Creates an NEG after an Ingress is created
spec: # Service's specification
  type: NodePort
  selector:
    run: neg-demo-app # Selects Pods labelled run: neg-demo-app
  ports:
  - port: 80 # Service's port
    protocol: TCP
    targetPort: 9376

サービスのアノテーション cloud.google.com/neg: '{"ingress": true}' によってコンテナ ネイティブの負荷分散が有効化されます。ただし、ロードバランサはサービスの Ingress を作成するまで作成されません。

このマニフェストを neg-demo-svc.yaml として保存してから、次のコマンドを実行してサービスを作成します。

kubectl apply -f neg-demo-svc.yaml

サービスの Ingress を作成する

次の Ingress のサンプル、neg-demo-ing では、作成したサービスをターゲットとしています。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: neg-demo-ing
spec:
  backend:
    serviceName: neg-demo-svc # Name of the Service targeted by the Ingress
    servicePort: 80 # Should match the port used by the Service

このマニフェストを neg-demo-ing.yaml として保存してから、次のコマンドを実行して Ingress を作成します。

kubectl apply -f neg-demo-ing.yaml

Ingress を作成すると、プロジェクト内に HTTP(S) ロードバランサが作成され、クラスタが実行される各ゾーンに NEG が作成されます。NEG 内のエンドポイントとサービスのエンドポイントは同期の状態が維持されます。

Ingress を確認する

ワークロードをデプロイし、ポッドをサービスにグループ化してサービスの Ingress を作成したら、Ingress によってコンテナ ネイティブのロードバランサが正常にプロビジョニングされていることを確認します。

Ingress のステータスを取得するには、次のコマンドを実行します。

kubectl describe ingress neg-demo-ing

コマンド出力で、ADDCREATE のイベントを探します。

Events:
Type     Reason   Age                From                     Message
----     ------   ----               ----                     -------
Normal   ADD      16m                loadbalancer-controller  default/neg-demo-ing
Normal   Service  4s                 loadbalancer-controller  default backend set to neg-demo-svc:32524
Normal   CREATE   2s                 loadbalancer-controller  ip: 192.0.2.0

ロードバランサ機能のテスト

以降のセクションでは、コンテナ ネイティブのロードバランサの機能をテストする方法について説明します。

Ingress の IP アドレスにアクセスする

HTTP(S) ロードバランサが構成されるまで数分待ちます。

Ingress の IP アドレスにアクセスすることで、コンテナ ネイティブのロードバランサが機能していることを確認できます。

Ingress の IP アドレスを取得するには、次のコマンドを実行します。

kubectl get ingress neg-demo-ing

コマンド出力の ADDRESS 列に、Ingress の IP アドレスが表示されます。この IP アドレスに、ウェブブラウザでアクセスします。

バックエンド サービスのヘルス ステータスをチェックする

ロードバランサのバックエンド サービスのヘルス ステータスを取得することもできます。

まず、プロジェクトで実行されているバックエンド サービスのリストを、次のようにして取得します。

gcloud compute backend-services list

サービスの名前を含むバックエンドの名前(neg-demo-svc など)をコピーします。その後、次のようにしてバックエンド サービスのヘルス ステータスを取得します。

gcloud compute backend-services get-health [BACKEND_SERVICE_NAME] --global

Ingress の機能を確認する

ロードバランサが期待どおりに機能しているかどうかをテストするもう 1 つの方法は、サンプルの Deployment をスケーリングし、テスト リクエストを Ingress に送信して、正しい数のレプリカが応答するかどうかを確認することです。

次のコマンドで、neg-demo-app Deployment を 1 つのインスタンスから 2 つのインスタンスにスケーリングします。

kubectl scale deployment neg-demo-app --replicas 2

ロールアウトが完了するまで数分待ちます。ロールアウトの完了を確認するには、次のコマンドを実行します。

kubectl get deployment neg-demo-app

コマンド出力で、使用可能なレプリカが 2 つあることを確認します。

NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
neg-demo-app   2         2         2            2           26m

さらに、次のコマンドを実行して、ロードバランサからの個別のレスポンスの数をカウントします。

for i in `seq 1 100`; do \
  curl --connect-timeout 1 -s [IP_ADDRESS] && echo; \
done  | sort | uniq -c

ここで、[IP_ADDRESS] は Ingress の IP アドレスです。Ingress の IP アドレスは、kubectl describe ingress neg-demo-ing から取得できます。

このコマンド出力で、個別のレスポンスの数がレプリカと同数である、すなわちすべてのバックエンド ポッドでトラフィックが処理されていることが示されているか確認します。

44 neg-demo-app-7f7dfd7bc6-dcn95
56 neg-demo-app-7f7dfd7bc6-jrmzf

クリーンアップ

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

クラスタの削除

gcloud

gcloud container clusters delete neg-demo-cluster

Console

  1. GCP Console で Google Kubernetes Engine のメニューにアクセスします。

    Google Kubernetes Engine のメニューにアクセスする

  2. neg-demo-cluster を選択します。

  3. [削除] をクリックします。

トラブルシューティング

ネットワーク構成を確認する方法は次のとおりです。以降のセクションでは、コンテナ ネイティブの負荷分散に関連する特定の問題を解決する方法について説明します。

  • ネットワーク エンドポイント グループを一覧表示する方法については、負荷分散のドキュメントをご覧ください。

  • サービスの neg-status アノテーションのサービスに対応する NEG の名前とゾーンを確認できます。サービスの仕様を取得するには、次のコマンドを実行します。

    kubectl get svc svc-name -o yaml

    metadata:annotations:cloud.google.com/neg-status アノテーションには、サービスの対応する NEG の名前と NEG のゾーンが一覧表示されます。

  • NEG に対応するバックエンド サービスのヘルスは、次のコマンドで確認できます。

    gcloud compute backend-service [--project PROJECT_NAME] \
      get-health BACKEND_SERVICE_NAME --global
    

    バックエンド サービスは NEG と同じ名前になっていることに注意してください。

  • サービスのイベントログを出力するには、次のコマンドを実行します。

    kubectl describe svc [SERVICE_NAME]
    

    サービスの名前文字列には、対応する GKE サービスの名前と名前空間が含まれます。

エイリアス IP を使用したクラスタを作成できない

現象
エイリアス IP を使用したクラスタを作成しようとすると、次のようなエラーが発生することがあります。
ResponseError: code=400, message=IP aliases cannot be used with a legacy network.
考えられる原因
作成しようとしているエイリアス IP 付きのクラスタでレガシー ネットワークも使用している場合、このエラーが発生します。
解決策
エイリアス IP とレガシー ネットワークの両方を使用するクラスタを作成しないようにします。エイリアス IP の詳しい使用方法については、エイリアス IP を使用した VPC ネイティブ クラスタの作成をご覧ください。

トラフィックがエンドポイントに到達しない

現象
502 エラーが発生するか、接続が拒否されます。
考えられる原因

新しいエンドポイントは、通常ロードバランサへの接続後に到達可能になりますが、そのためにはヘルスチェックにレスポンスを返す必要があります。トラフィックがエンドポイントに到達しない場合、502 エラーが発生したり、接続が拒否されたりします。

502 エラーと接続の拒否は SIGTERM を処理しないコンテナが原因である可能性もあります。コンテナが SIGTERM を明示的に処理しない場合は、直ちに終了し、リクエストの処理を停止します。ロードバランサは、終了したコンテナに受信トラフィックを送信し続け、エラーにつながります。

解決策

コンテナを構成して SIGTERM を処理し、終了猶予期間中はリクエストへの応答を続行します。デフォルトでは 30 秒です。SIGTERM を受信したときにヘルスチェックが失敗するようにポッドを構成します。これにより、エンドポイントのデプログラミング中に、ポッドへのトラフィックの送信を停止するようにロードバランサに通知します。

詳細については、ポッド終了に関するドキュメントポッド終了のベスト プラクティスに関する投稿をご覧ください。

エンドポイントに到達しないトラフィックをトラブルシューティングするには、ファイアウォール ルールで 130.211.0.0/2235.191.0.0/16 の範囲のエンドポイントへの受信 TCP トラフィックが許可されていることを確認します。詳細については、Cloud Load Balancing ドキュメントのヘルスチェックの追加をご覧ください。

プロジェクトのバックエンド サービスを確認します。関連するバックエンド サービスの名前文字列には、対応する Google Kubernetes Engine サービスの名前と名前空間が含まれます。

gcloud compute backend-services list

バックエンド サービスからバックエンドのヘルス ステータスを取得します。

gcloud compute backend-services get-health [BACKEND_SERVICE_NAME]

すべてのバックエンドでヘルス ステータスが異常な場合は、ファイアウォール、Ingress、サービスのいずれかの構成が不適切である可能性があります。

一部のバックエンドで短期間ヘルス ステータスが異常な場合は、ネットワーク プログラミングのレイテンシが原因である可能性があります。

一部のバックエンドがバックエンド サービスのリストに表示されない場合は、プログラミングのレイテンシが原因である可能性があります。これは、次のコマンドを実行して確認できます。ここで、[NEG] はバックエンド サービスの名前です(NEG とバックエンド サービスは同じ名前を共有します)。

gcloud compute network-endpoint-groups list-network-endpoints [NEG]

予期されるすべてのエンドポイントが NEG に存在することを確認します。

停滞時のロールアウト

現象
更新した Deployment がロールアウトし、最新のレプリカの数が目的のレプリカの数と一致しません。
考えられる原因

デプロイのヘルスチェックが失敗しています。コンテナ イメージが不適切であるか、ヘルスチェックが正しく構成されていない可能性があります。ポッドのローリングの置換は、新しく開始したポッドがポッドの readiness ゲートを通過してから行います。これは、ポッドがロードバランサのヘルスチェックに応答している場合にのみ発生します。ポッドが応答しない場合、またはヘルスチェックが正しく構成されていない場合は、readiness ゲートの条件を満たせず、ロールアウトを続行できません。

kubectl 1.13 以降を使用している場合は、次のコマンドでポッドの readiness ゲートのステータスを確認できます。

kubectl get my-Pod -o wide

READINESS GATES 列を確認します。

この列は、kubectl 1.12 以下には存在しません。READY 状態であるとマークされたポッドは、readiness ゲートに失敗した可能性があります。これを確認するには、次のコマンドを使用します。

kubectl get my-pod -o yaml

readiness ゲートとそのステータスが出力に一覧表示されます。

解決策

Deployment のポッドの仕様のコンテナ イメージが正しく機能し、ヘルスチェックに応答できることを確認します。ヘルスチェックが正しく構成されていることを確認します。

既知の問題

Google Kubernetes Engine のコンテナ ネイティブの負荷分散には、次のような既知の問題があります。

不完全なガベージ コレクション

Google Kubernetes Engine のガベージ コレクションは、コンテナ ネイティブのロードバランサを 2 分ごとに収集します。ロードバランサが完全に削除される前にクラスタが削除された場合は、ロードバランサの NEG を手動で削除する必要があります。

次のコマンドを実行して、プロジェクト内の NEG を表示します。

gcloud compute network-endpoint-groups list

コマンド出力で、関連する NEG を探します。

NEG を削除するには、次のコマンドを実行します。ここで、[NEG] は NEG の名前です。

gcloud compute network-endpoint-groups delete [NEG]

ワークロードのロールアウトとエンドポイントの伝播の調整

ワークロードをクラスタにデプロイするときや、既存のワークロードを更新するときに、コンテナ ネイティブのロードバランサでは、ワークロードのロールアウトの完了に要する時間よりも、新しいエンドポイントの伝播に要する時間のほうが長くなる場合があります。このガイドで使用するサンプルの Deployment では、ロールアウトとエンドポイントの伝播の調整に terminationGracePeriodSecondsminReadySeconds という 2 つのフィールドを使用しています。

terminationGracePeriodSeconds を指定すると、ポッドの削除がスケジュール設定された後に接続が終了するまで待ってから、ポッドを正常にシャットダウンできます。

minReadySeconds では、ポッドが作成された後のレイテンシ期間を追加します。新しいポッドがコンテナのクラッシュを発生させることなく Ready ステータスになるまでの最短秒数を指定します。この期間が経過するとポッドは使用可能と見なされます。

ワークロードのロールアウトが原因でサービスが中断されないように、ワークロードの minReadySecondsterminationGracePeriodSeconds の値は 60 秒以上に構成する必要があります。

terminationGracePeriodSeconds はすべてのポッド仕様で使用でき、minReadySeconds は Deployment と DaemonSets で使用できます。

ロールアウトを微調整する方法について詳しくは、RollingUpdateStrategy をご覧ください。

次のステップ

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

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

Kubernetes Engine のドキュメント