このページでは、Google Kubernetes Engine(GKE)でコンテナ ネイティブのロード バランシングを使用する方法について説明します。コンテナ ネイティブのロード バランシングにより、ロードバランサは Kubernetes Pod を直接ターゲットにして、トラフィックを Pod に均等に分配できます。
コンテナ ネイティブのロード バランシングのメリット、要件、制限事項の詳細については、コンテナ ネイティブのロード バランシングをご覧ください。
始める前に
作業を始める前に、次のことを確認してください。
- Google Kubernetes Engine API を有効にする。 Google Kubernetes Engine API の有効化
- このタスクに Google Cloud CLI を使用する場合は、gcloud CLI をインストールして初期化する。すでに gcloud CLI をインストールしている場合は、
gcloud components update
を実行して最新のバージョンを取得する。
コンテナ ネイティブのロード バランシングを使用する
以下のセクションでは、GKE でのコンテナ ネイティブのロード バランシングの構成について説明します。GKE クラスタ 1.17 以降と一定の条件下では、コンテナ ネイティブのロード バランシングがデフォルトであり、明示的な cloud.google.com/neg: '{"ingress": true}'
Service のアノテーションは必要ありません。
VPC ネイティブ クラスタを作成する
コンテナ ネイティブのロード バランシングを使用するには、GKE クラスタでエイリアス IP を有効にする必要があります。
たとえば、次のコマンドは、自動プロビジョニングされたサブネットワークを使用して、GKE クラスタ neg-demo-cluster
を作成します。
Autopilot モードでは、エイリアス IP アドレスがデフォルトで有効になっています。
gcloud container clusters create-auto neg-demo-cluster \ --location=COMPUTE_LOCATION
COMPUTE_LOCATION
は、クラスタの Compute Engine のロケーションに置き換えます。
Standard モードの場合は、クラスタの作成時にエイリアス IP アドレスを有効にします。
gcloud container clusters create neg-demo-cluster \ --enable-ip-alias \ --create-subnetwork="" \ --network=default \ --zone=us-central1-a
Deployment を作成する
次の Deployment のサンプル(neg-demo-app
)では、コンテナ化された HTTP サーバーの単一インスタンスが実行されます。Pod の readiness フィードバックを使用するワークロードを使用することをおすすめします。
Pod の 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: registry.k8s.io/serve_hostname:v1.4 # Application to run in Deployment's Pods name: hostname # Container name ports: - containerPort: 9376 protocol: TCP
ハードコードされた遅延を使用する
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: registry.k8s.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 ports: - containerPort: 9376 protocol: TCP terminationGracePeriodSeconds: 60 # Number of seconds to wait for connections to terminate before shutting down Pods
この Deployment では、各コンテナで HTTP サーバーが実行されます。HTTP サーバーは、アプリケーション サーバーのホスト名(サーバーが実行されている Pod の名前)をレスポンスとして返します。
このマニフェストを neg-demo-app.yaml
として保存し、Deployment を作成します。
kubectl apply -f neg-demo-app.yaml
コンテナ ネイティブのロードバランサに Service を作成する
Deployment を作成したら、Pod を Service にグループ化する必要があります。
次のサンプルの Service neg-demo-svc
は、前のセクションで作成したサンプルの Deployment をターゲットにしています。
apiVersion: v1
kind: Service
metadata:
name: neg-demo-svc # Name of Service
annotations:
cloud.google.com/neg: '{"ingress": true}' # Creates a NEG after an Ingress is created
spec: # Service's specification
type: ClusterIP
selector:
run: neg-demo-app # Selects Pods labelled run: neg-demo-app
ports:
- name: http
port: 80 # Service's port
protocol: TCP
targetPort: 9376
Service のアノテーション cloud.google.com/neg: '{"ingress": true}'
によってコンテナネイティブのロード バランシングが有効化されます。ただし、ロードバランサは Service の Ingress を作成するまで作成されません。
このマニフェストを neg-demo-svc.yaml
として保存し、Service を作成します。
kubectl apply -f neg-demo-svc.yaml
Service の Ingress を作成する
次の Ingress のサンプル(neg-demo-ing
)では、作成した Service をターゲットとしています。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: neg-demo-ing
spec:
defaultBackend:
service:
name: neg-demo-svc # Name of the Service targeted by the Ingress
port:
number: 80 # Should match the port used by the Service
このマニフェストを neg-demo-ing.yaml
として保存し、Ingress を作成します。
kubectl apply -f neg-demo-ing.yaml
Ingress を作成すると、プロジェクト内にアプリケーション ロードバランサが作成され、クラスタが実行される各ゾーンにネットワーク エンドポイント グループ(NEG)が作成されます。NEG 内のエンドポイントと Service のエンドポイントは同期の状態が維持されます。
Ingress を確認する
ワークロードをデプロイし、Pod を Service にグループ化して Service の Ingress を作成したら、Ingress によってコンテナ ネイティブのロードバランサが正常にプロビジョニングされていることを確認します。
Ingress のステータスを取得します。
kubectl describe ingress neg-demo-ing
出力には、ADD
イベントと CREATE
イベントが含まれます。
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 アドレスにアクセスする
アプリケーション ロードバランサが構成されるまで数分待ちます。
Ingress の IP アドレスにアクセスすることで、コンテナ ネイティブのロードバランサが機能していることを確認できます。
Ingress の IP アドレスを取得するには、次のコマンドを実行します。
kubectl get ingress neg-demo-ing
コマンド出力の ADDRESS
列に、Ingress の IP アドレスが表示されます。この IP アドレスに、ウェブブラウザでアクセスします。
バックエンド サービスのヘルス ステータスをチェックする
ロードバランサのバックエンド サービスのヘルス ステータスを取得することもできます。
プロジェクトで実行されているバックエンド サービスのリストを取得します。
gcloud compute backend-services list
Service の名前を含むバックエンド サービスの名前(
neg-demo-svc
など)を記録します。バックエンド サービスの稼働状況を取得します。
gcloud compute backend-services get-health BACKEND_SERVICE_NAME --global
BACKEND_SERVICE_NAME
は、バックエンド サービスの名前に置き換えます。
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
Ingress の IP アドレスを取得します。
kubectl describe ingress neg-demo-ing
このコマンドで 404 エラーが返された場合は、ロードバランサが起動するまで数分待ってからもう一度お試しください。
ロードバランサからの個別のレスポンスの数をカウントします。
for i in `seq 1 100`; do \ curl --connect-timeout 1 -s IP_ADDRESS && echo; \ done | sort | uniq -c
IP_ADDRESS
は、Ingress の IP アドレスに置き換えます。出力は次のようになります。
44 neg-demo-app-7f7dfd7bc6-dcn95 56 neg-demo-app-7f7dfd7bc6-jrmzf
この出力では、個別のレスポンスの数はレプリカの数と同じです。これは、すべてのバックエンド Pod がトラフィックを処理していることを示しています。
クリーンアップ
このページのタスクを完了したら、アカウントで不要な請求が発生しないように、以下の手順でリソースを削除します。
クラスタの削除
gcloud
gcloud container clusters delete neg-demo-cluster
コンソール
Google Cloud コンソールで [Google Kubernetes Engine] ページに移動します。
neg-demo-cluster を選択し、delete [削除] をクリックします。
確認のメッセージが表示されたら、[削除] をクリックします。
トラブルシューティング
ネットワーク構成を確認する方法は次のとおりです。以降のセクションでは、コンテナ ネイティブのロード バランシングに関連する特定の問題の解決方法について説明します。
ネットワーク エンドポイント グループを一覧表示する方法については、負荷分散のドキュメントをご覧ください。
サービスの
neg-status
アノテーションのサービスに対応する NEG の名前とゾーンを確認できます。サービスの仕様を取得するには、次のコマンドを実行します。kubectl get svc SVC_NAME -o yaml
metadata:annotations:cloud.google.com/neg-status
アノテーションには、サービスの対応する NEG の名前と NEG のゾーンが一覧表示されます。NEG に対応するバックエンド サービスのヘルスは、次のコマンドで確認できます。
gcloud compute backend-services --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 の使用方法については、VPC ネイティブ クラスタを作成するをご覧ください。
トラフィックがエンドポイントに到達しない
- 現象
- 502 / 503 エラーが発生するか、接続が拒否されます。
- 考えられる原因
新しいエンドポイントは、通常ロードバランサへの接続後に到達可能になりますが、そのためにはヘルスチェックにレスポンスを返す必要があります。トラフィックがエンドポイントに到達しない場合、502 エラーが発生することがあります。また、接続が拒否されることもあります。
502 エラーと接続の拒否は
SIGTERM
を処理しないコンテナが原因である可能性もあります。コンテナがSIGTERM
を明示的に処理しない場合は、直ちに終了し、リクエストの処理を停止します。ロードバランサは、終了したコンテナに受信トラフィックを送信し続け、エラーにつながります。コンテナ ネイティブのロードバランサには、バックエンドのエンドポイントが 1 つだけ含まれます。ローリング アップデート中は、新しいエンドポイントがプログラムされる前に古いエンドポイントがプログラム解除されます。
コンテナ ネイティブのロードバランサのプロビジョニング後、バックエンド Pod が初めて新しいゾーンにデプロイされます。ゾーンに 1 つ以上のエンドポイントがある場合、ロードバランサのインフラストラクチャはゾーンでプログラムされます。ゾーンに新しいエンドポイントが追加されると、ロードバランサ インフラストラクチャがプログラムされ、サービスの中断が発生します。
- 解決策
コンテナを構成して
SIGTERM
を処理し、終了猶予期間中はリクエストへの応答を続行します。デフォルトでは 30 秒です。SIGTERM
を受信したときにヘルスチェックが失敗するように Pod を構成します。これにより、エンドポイントのデプログラミング中に、Pod へのトラフィックの送信を停止するようにロードバランサに通知します。エンドポイントのプログラム解除中に
SIGTERM
を受け取ったとき、アプリケーションが正常にシャットダウンせず、リクエストへの応答を停止している場合は、preStop フックを使用してSIGTERM
を処理し、トラフィックの処理を継続できます。lifecycle: preStop: exec: # if SIGTERM triggers a quick exit; keep serving traffic instead command: ["sleep","60"]
Pod の終了に関するドキュメントをご覧ください。
ロードバランサのバックエンドにインスタンスが 1 つしかない場合は、新しいインスタンスが完全にプログラムされる前にそのインスタンスを破棄しないようにロールアウト手順を構成してください。
Deployment
ワークロードが管理するアプリケーション Pod では、maxUnavailable
パラメータが0
に設定されているロールアウト手順を構成することでこれを実現できます。strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0
エンドポイントに到達しないトラフィックをトラブルシューティングするには、ファイアウォール ルールで
130.211.0.0/22
と35.191.0.0/16
の範囲のエンドポイントへの受信 TCP トラフィックが許可されていることを確認します。詳細については、Cloud Load Balancing ドキュメントのヘルスチェックの追加をご覧ください。プロジェクトのバックエンド サービスを確認します。関連するバックエンド サービスの名前文字列には、対応する GKE サービスの名前と名前空間が含まれます。
gcloud compute backend-services list
バックエンド サービスからバックエンドのヘルス ステータスを取得します。
gcloud compute backend-services get-health BACKEND_SERVICE_NAME
すべてのバックエンドでヘルス ステータスが異常な場合は、ファイアウォール、Ingress、Service のいずれかの構成が不適切である可能性があります。
一部のバックエンドで短期間ヘルス ステータスが異常な場合は、ネットワーク プログラミングのレイテンシが原因である可能性があります。
一部のバックエンドがバックエンド サービスのリストに表示されない場合は、プログラミングのレイテンシが原因である可能性があります。これは、次のコマンドを実行して確認できます。ここで、
NEG_NAME
はバックエンド サービスの名前です(NEG とバックエンド サービスは同じ名前を共有します)。gcloud compute network-endpoint-groups list-network-endpoints NEG_NAME
予期されるすべてのエンドポイントが NEG に存在することを確認します。
コンテナ ネイティブのロードバランサによって少数のバックエンド(たとえば 1 つの Pod)が選択される場合、レプリカの数を増やし、GKE クラスタがまたがるすべてのゾーンにバックエンド Pod を分散することを検討してください。これにより、基盤となるロードバランサのインフラストラクチャが完全にプログラムされます。それ以外の場合は、バックエンド Pod を単一のゾーンに制限することを検討してください。
エンドポイントのネットワーク ポリシーを構成する場合は、プロキシ専用サブネットからの上り(内向き)が許可されていることを確認します。
停滞時のロールアウト
- 現象
- 更新した Deployment がロールアウトし、最新のレプリカの数が目的のレプリカの数と一致しません。
- 考えられる原因
デプロイのヘルスチェックが失敗しています。コンテナ イメージが不適切であるか、ヘルスチェックが正しく構成されていない可能性があります。Pod のローリング置換は、新しく開始した Pod が Pod の readiness ゲートを通過してから行います。これは、Pod がロードバランサのヘルスチェックに応答している場合にのみ発生します。Pod が応答しない場合、またはヘルスチェックが正しく構成されていない場合は、readiness ゲートの条件を満たせず、ロールアウトを続行できません。
kubectl
1.13 以降を使用している場合は、次のコマンドで Pod の readiness ゲートのステータスを確認できます。kubectl get pod POD_NAME -o wide
READINESS GATES
列を確認します。この列は、
kubectl
1.12 以下には存在しません。READY
状態であるとマークされた Pod は、readiness ゲートに失敗した可能性があります。これを確認するには、次のコマンドを使用します。kubectl get pod POD_NAME -o yaml
readiness ゲートとそのステータスが出力に一覧表示されます。
- 解決策
Deployment の Pod の仕様のコンテナ イメージが正しく機能し、ヘルスチェックに応答できることを確認します。ヘルスチェックが正しく構成されていることを確認します。
デグレード モードのエラー
- 現象
GKE バージョン 1.29.2-gke.1643000 以降では、NEG が更新されると、ログ エクスプローラでサービスに関して次の警告が表示されることがあります。
Entering degraded mode for NEG <service-namespace>/<service-name>-<neg-name>... due to sync err: endpoint has missing nodeName field
- 考えられる原因
これらの警告は、
EndpointSlice
オブジェクトに基づく NEG の更新中に GKE がエンドポイントの構成ミスを検出し、より詳細な計算プロセス(デグレード モード)をトリガーしたことを示します。GKE は、構成の誤りを修正するか、無効なエンドポイントを NEG の更新から除外することで、引き続きベスト エフォート方式で NEG を更新します。よくあるエラーには、次のようなものがあります。
endpoint has missing pod/nodeName field
endpoint corresponds to an non-existing pod/node
endpoint information for attach/detach operation is incorrect
- 解決策
通常、これは一時的な状態が原因で発生するイベントであり、自動的に修正されます。ただし、カスタム
EndpointSlice
オブジェクトの誤った構成によってイベントが発生した場合は解決されません。構成の誤りを確認するには、サービスに対応するEndpointSlice
オブジェクトを調べます。kubectl get endpointslice -l kubernetes.io/service-name=<service-name>
イベントのエラーに基づいてエンドポイントを検証します。
この問題を解決するには、
EndpointSlice
オブジェクトを手動で変更する必要があります。更新によって NEG がトリガーされ、再度更新されます。誤った構成がなくなると、出力は次のようになります。NEG <service-namespace>/<service-name>-<neg-name>... is no longer in degraded mode
既知の問題
GKE のコンテナ ネイティブのロード バランシングには、次のような既知の問題があります。
不完全なガベージ コレクション
GKE のガベージ コレクションは、コンテナ ネイティブのロードバランサを 2 分ごとに収集します。ロードバランサが完全に削除される前にクラスタが削除された場合は、ロードバランサの NEG を手動で削除する必要があります。
次のコマンドを実行して、プロジェクト内の NEG を表示します。
gcloud compute network-endpoint-groups list
コマンド出力で、関連する NEG を探します。
NEG を削除するには、次のコマンドを実行します。NEG_NAME
は NEG の名前に置き換えます。
gcloud compute network-endpoint-groups delete NEG_NAME
ワークロードのロールアウトとエンドポイントの伝播を調整する
ワークロードをクラスタにデプロイするときや、既存のワークロードを更新するときに、コンテナ ネイティブのロードバランサでは、ワークロードのロールアウトの完了に要する時間よりも、新しいエンドポイントの伝播に要する時間のほうが長くなる場合があります。このガイドでデプロイするサンプルの Deployment では、ロールアウトとエンドポイントの伝播の調整に terminationGracePeriodSeconds
と minReadySeconds
という 2 つのフィールドを使用しています。
terminationGracePeriodSeconds
を指定すると、Pod の削除がスケジュール設定された後に接続が終了するまで待ってから、Pod を正常にシャットダウンできます。
minReadySeconds
では、Pod が作成された後のレイテンシ期間を追加します。新しい Pod がコンテナのクラッシュを発生させることなく Ready
ステータスになるまでの最短秒数を指定します。この期間が経過すると Pod は使用可能と見なされます。
ワークフローのロールアウトでサービスが中断しないように、ワークロードの minReadySeconds
と terminationGracePeriodSeconds
の値は 60 秒以上に構成する必要があります。
terminationGracePeriodSeconds
はすべての Pod 仕様で、minReadySeconds
は Deployment と DaemonSets で使用できます。
ロールアウトを微調整する方法について詳しくは、RollingUpdateStrategy をご覧ください。
Pod readinessProbe
の initialDelaySeconds
が認識されない
コンテナ ネイティブのロードバランサによって Pod の readinessProbe
の initialDelaySeconds
構成が認識されると思われるかもしれませんが、readinessProbe
は kubelet によって実装され、initialDelaySeconds
構成はコンテナ ネイティブのロードバランサではなく kubelet のヘルスチェックを制御します。コンテナ ネイティブのロード バランシングには、独自のヘルスチェックがあります。