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

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

概要

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

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

利点

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

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

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

要件

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

Google Kubernetes Engine バージョン 1.10
コンテナ ネイティブのロードバランサは、Google Kubernetes Engine バージョン 1.10 以降を実行する Google Kubernetes Engine クラスタで使用できます。
VPC ネイティブ
コンテナ ネイティブの負荷分散を使用するには、クラスタが VPC ネイティブである必要があります。詳細については、エイリアス IP を使用した VPC ネイティブ クラスタの作成をご覧ください。

制限事項

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

制限事項

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

料金

このガイドに沿って作成した 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 サーバーの単一インスタンスが実行されます。

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: neg-demo-app # Label for the Deployment
  name: neg-demo-app # Name of Deployment
spec: # Deployment's specification
  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
      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 beta 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. [削除] をクリックします。

トラブルシューティング

以降のセクションでは、コンテナ ネイティブの負荷分散に関連する一般的な問題を解決する方法について説明します。

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

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

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

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

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

プロジェクトのバックエンド サービスを確認します。関連するバックエンド サービスには、対応する Google Kubernetes Engine サービスの名前が付いています。

gcloud beta compute backend-services list

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

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

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

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

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

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

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

既知の問題

Google Kubernetes Engine 上でベータ版のコンテナ ネイティブの負荷分散を使用する際には、次の既知の問題があります。

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

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

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

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

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

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

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

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

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

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

gcloud beta compute network-endpoint-groups list

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

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

gcloud beta compute network-endpoint-groups delete [NEG]

ワークロードのゼロへのスケーリングによる中断

ワークロードをゼロにスケーリングすると、NEG 内のエンドポイントの数がゼロからゼロ以外に、またはその逆に移行するときに一時的な中断が発生することがあります。このような中断時にはロードバランサが 200 以外のレスポンスを返すことがあるため、バックエンドのヘルスに異常が発生しているように見える場合があります。

次のステップ

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

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

Kubernetes Engine のドキュメント