内部 TCP / UDP 負荷分散

このページでは、Google Kubernetes Engine で Compute Engine 内部 TCP / UDP ロードバランサを作成する方法について説明します。

概要

内部 TCP / UDP 負荷分散を使用すると、同じ VPC ネットワークを使用し、同じ Google Cloud リージョンに配置されているクラスタ外のアプリケーションに、クラスタのサービスがアクセスできるようになります。たとえば、us-west1 リージョンにクラスタを配置している場合、そのクラスタのサービスの 1 つが、同じ VPC ネットワークを使用し、このリージョンで実行されている Compute Engine VM インスタンスにアクセスできるようになります。

内部 TCP / UDP ロードバランサを作成するには、cloud.google.com/load-balancer-type: "Internal" アノテーションを含む Service リソースと type: LoadBalancer 仕様を作成します。以下では、これらの例と作成方法について説明します。

内部 TCP / UDP 負荷分散を使用しない場合は、外部ロードバランサとファイアウォール ルールを設定して、クラスタの外部からアプリケーションにアクセスできるようにする必要があります。

内部 TCP / UDP 負荷分散では、同じコンピューティング リージョン内のネットワークでトラフィックを受信するクラスタにプライベート IP アドレス(RFC 1918)を作成します。

料金

Compute Engine の料金モデルに従って課金されます。詳細については、負荷分散と転送ルールの料金をご覧ください。また、Google Cloud 料金計算ツールに関する Compute Engine のページもご覧ください。

始める前に

このタスクの準備として、次の手順を行います。

  • Google Kubernetes Engine API が有効になっていることを確認します。
  • Enable Google Kubernetes Engine API を有効にする
  • Cloud SDK がインストール済みであることを確認します。
  • デフォルトのプロジェクト ID を設定します。
    gcloud config set project [PROJECT_ID]
  • ゾーンクラスタを使用する場合は、デフォルトのコンピューティング ゾーンを設定します。
    gcloud config set compute/zone [COMPUTE_ZONE]
  • リージョン クラスタを使用する場合は、デフォルトのコンピューティング リージョンを設定します。
    gcloud config set compute/region [COMPUTE_REGION]
  • gcloud を最新バージョンに更新します。
    gcloud components update

Deployment を作成する

以下のマニフェストは、Hello World アプリの 3 つのレプリカを実行する Deployment を記述しています。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-app
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 3
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: "gcr.io/google-samples/hello-app:2.0"

このサンプルアプリのソースコードと Dockerfile は GitHub で入手できます。PORT 環境変数が指定されていないため、コンテナはデフォルト ポート 8080 でリッスンします。

Deployment を作成するには、マニフェストから my-deployment.yaml ファイルを作成し、シェルまたはターミナル ウィンドウで次のコマンドを実行します。

kubectl apply -f my-deployment.yaml

内部 TCP ロードバランサを作成する

以降のセクションでは、Service を使用して内部 TCP ロードバランサを作成する方法について説明します。

Service 構成ファイルの作成

内部 TCP ロードバランサを作成する Service の例を次に示します。

apiVersion: v1
kind: Service
metadata:
  name: ilb-service
  annotations:
    cloud.google.com/load-balancer-type: "Internal"
  labels:
    app: hello
spec:
  type: LoadBalancer
  selector:
    app: hello
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP

Service の最小要件

マニフェストには次のものを含める必要があります。

  • Service の name。この場合 ilb-service です。
  • アノテーション: cloud.google.com/load-balancer-type: "Internal"。内部 TCP / UDP ロードバランサが構成されることを指定します。
  • type: LoadBalancer
  • spec: selector フィールド。Service が対象にするポッドを指定します。例: app: hello
  • port には、Service が公開されるポートを指定します。targetPort には、コンテナがリッスンするポートを指定します。

Service のデプロイ

内部 TCP ロードバランサを作成するには、マニフェストから my-service.yaml ファイルを作成し、シェルまたはターミナル ウィンドウで次のコマンドを実行します。

kubectl apply -f my-service.yaml

Service の検査

デプロイ後、Service を検査し、正常に構成されていることを確認します。

Service に関する詳細情報を取得します。

kubectl get service ilb-service --output yaml

出力の status.loadBalancer.ingress の下に、内部ロードバランサの IP アドレスが表示されます。これは、clusterIP の値と異なります。この例の場合、ロードバランサの IP アドレスは 10.128.15.193 です。

apiVersion: v1
kind: Service
metadata:
  ...
  labels:
    app: hello
  name: ilb-service
  ...
spec:
  clusterIP: 10.0.9.121
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30835
    port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: hello
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 10.128.15.193

app: hello というラベルを持つポッドは、この Service のメンバーです。これらは、内部ロードバランサに送信されたリクエストを最後に受信するポッドになります。

クライアントは、Service マニフェストの port フィールドに指定された loadBalancer IP アドレスと TCP ポートを使用して Service を呼び出します。リクエストは、targetPort フィールドに指定された TCP ポートのいずれかのメンバーポッドに転送されます。前の例では、クライアントは 10.128.15.193 の TCP ポート 80 で Service を呼び出します。リクエストは、いずれかのメンバーポッドの TCP ポート 8080 に転送されます。メンバーポッドには、ポート 8080 をリッスンするコンテナが必要です。

nodePort 値 30835 は無関係です。内部ロードバランサには関係ありません。

ロードバランサの転送ルールの表示

内部ロードバランサは転送ルールとして実装されています。転送ルールにはバックエンド サービスが設定され、このサービスにはインスタンス グループが設定されています。

内部ロードバランサのアドレス(前の例では 10.128.15.193)は転送ルールのアドレスと同じです。内部ロードバランサを実装する転送ルールを確認するには、プロジェクト内のすべての転送ルールのリストを取得します。

gcloud compute forwarding-rules list --filter="loadBalancingScheme=INTERNAL"

出力で、内部ロードバランサと同じアドレスの転送ルールを探します(この例では 10.128.15.193)。

NAME                          ... IP_ADDRESS  ... TARGET
...
aae3e263abe0911e9b32a42010a80008  10.128.15.193   us-central1/backendServices/aae3e263abe0911e9b32a42010a80008

出力には、関連するバックエンド サービスも表示されます(この例では ae3e263abe0911e9b32a42010a80008)。

バックエンド サービスの説明:

gcloud compute backend-services describe aae3e263abe0911e9b32a42010a80008 --region us-central1

出力には、関連するインスタンス グループが表示されます(この例では k8s-ig--2328fa39f4dc1b75)。

backends:
- balancingMode: CONNECTION
  group: .../us-central1-a/instanceGroups/k8s-ig--2328fa39f4dc1b75
...
kind: compute#backendService
loadBalancingScheme: INTERNAL
name: aae3e263abe0911e9b32a42010a80008
...

Service の抽象化の仕組み

パケットが転送ルールで処理されると、パケットはいずれかのクラスタノードに転送されます。パケットがクラスタノードに到着すると、アドレスとポートは次のようになります。

宛先 IP アドレス転送ルール。この例では 10.128.15.193 です。
宛先 TCP ポートService の port フィールド。この例では 80 です。

転送ルール(つまり内部ロードバランサ)は、宛先 IP アドレスまたは宛先ポートを変更しません。代わりに、クラスタノードの iptables ルールにより、パケットが適切なポッドにルーティングされます。iptables ルールは、宛先 IP アドレスをポッドの IP アドレスに変更し、宛先ポートを Service の targetPort 値(この例では 8080)に変更します。

内部 TCP ロードバランサの確認

VM インスタンスに SSH で接続し、次のコマンドを実行します。

curl [LOAD_BALANCER_IP]

[LOAD_BALANCER_IP] は自分の LoadBalancer Ingress IP アドレスです。

レスポンスには hello-app の出力が含まれます。

Hello, world!
Version: 2.0.0
Hostname: hello-app-77b45987f7-pw54n

同じ VPC ネットワークの外部または同じリージョンの外部からコマンドを実行すると、タイムアウト エラーが発生します。

クラスタノードから内部ロードバランサに送信されるパケット

クラスタノードで実行中のプロセスが内部 TCP / UDP ロードバランサにパケットを送信したとします。パケットが転送される方法は、ロードバランサの作成時に使用した Service の externalTrafficPolicy によって異なります。転送動作は、ノードにその Service のメンバーポッドがあるかどうかによっても異なります。

次の表に、転送動作の概要を示します。

externalTrafficPolicyメンバーポッドを実行しているノードかノードで実行中のプロセスから送信されたパケットの動作
クラスタはいパケットは、同じノードまたは別のノードのメンバーポッドに配信されます。
クラスタいいえパケットは、別のノードにあるメンバーポッドに配信されます。
ローカルはいパケットは、同じノードのメンバーポッドに配信されます。
ローカルいいえ

Kubernetes 1.14 以前: パケットはドロップされます。

Kubernetes 1.15 以降: パケットは、別のノードのメンバーポッドに配信されます。

クリーンアップ

Deployment と Service を削除するには、kubectl delete または Cloud Console を使用します。

kubectl

Deployment を削除する

Deployment を削除するには、次のコマンドを実行します。

kubectl delete deployment hello-app

Service を削除する

Service を削除するには、次のコマンドを実行します。

kubectl delete service ilb-service

Console

Deployment を削除する

Deployment を削除するには、次の手順を行います。

  1. Cloud Console で Google Kubernetes Engine の [ワークロード] メニューに移動します。

    [ワークロード] メニューに移動

  2. メニューから、目的のワークロードを選択します。

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

  4. 確認ダイアログのメニューで、[削除] をクリックします。

Service を削除する

Service を削除するには、次の手順を行います。

  1. Cloud Console で Google Kubernetes Engine の [サービス] メニューに移動します。

    [サービス] メニューに移動

  2. メニューから目的の Service を選択します。

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

  4. 確認ダイアログのメニューで、[削除] をクリックします。

既存の Ingress に関する考慮事項

内部 TCP / UDP ロードバランサと分散モード UTILIZATION を使用する Ingress の両方を使用することはできません。Ingress と内部 TCP / UDP 負荷分散の両方を使用するには、Ingress で分散モード RATE を使用する必要があります。

クラスタに存在する Ingress リソースが Kubernetes バージョン 1.7.1 以前で作成されている場合、内部 TCP / UDP ロードバランサと互換性はありません。Kubernetes Ingress Resources オブジェクトによって作成された、以前の BackendService リソースは、分散モードを指定しないで作成されています。この API では、HTTP ロードバランサについてはデフォルトでバランシング モード UTILIZATION が使用されていました。しかし、内部 TCP / UDP ロードバランサでは、UTILIZATION を使って他のロードバランサを使用するインスタンス グループを指すことができません。

Ingress 分散モードの確認

Ingress 分散モードを確認するには、シェルまたはターミナル ウィンドウから次のコマンドを実行します。

GROUPNAME=`kubectl get configmaps ingress-uid -o jsonpath='k8s-ig--{.data.uid}' --namespace=kube-system`
gcloud compute backend-services list --format="table(name,backends[].balancingMode,backends[].group)" | grep $GROUPNAME

これらのコマンドによって、シェル変数 GROUPNAME がエクスポートされます。これによってクラスタのインスタンス グループ名が取得されます。次に、プロジェクトの Compute Engine backend service リソースがポーリングされ、$GROUPNAME の内容に従って結果が絞り込まれます。

出力は次のようになります。

k8s-be-31210--...  [u'RATE']       us-central1-b/instanceGroups/k8s-ig--...
k8s-be-32125--...  [u'RATE']       us-central1-b/instanceGroups/k8s-ig--...

出力で RATE エントリが返された場合またはエントリが返されなかった場合、内部ロードバランサは互換性があります。追加作業は必要ありません。

出力で UTILIZATION とマークされたエントリが返された場合、Ingress は互換性がありません。

Ingress リソースを更新して内部 TCP / UDP ロードバランサとの互換性を維持するには、Kubernetes バージョン 1.7.2 以降で新しいクラスタを作成し、サービスをそのクラスタに移行します。

その他の Service パラメータ

内部 TCP / UDP ロードバランサは、loadBalancerSourceRanges などの Service パラメータをサポートします。

  • VPC ネットワーク、サブネットワーク、VPN ゲートウェイが使用する 1 つ以上の RFC 1918 範囲を指定する spec: loadBalancerSourceRanges 配列。loadBalancerSourceRanges は、ロードバランサ経由のトラフィックをこのフィールドに指定された IP に制限します。このフィールドを手動で設定しない場合、このフィールドはデフォルトの 0.0.0.0 に設定され、すべての IPv4 トラフィックがノードに配信されます。

  • spec: loadBalancerIP を使用すると、ロードバランサに特定の IP アドレスを選択できます。他の内部 TCP / UDP ロードバランサまたは Service で使用されていない IP アドレスを選択する必要があります。省略した場合、エフェメラル IP が割り当てられます。詳細については、静的内部 IP アドレスの予約をご覧ください。

loadBalancerSourceRanges を構成して内部 TCP / UDP ロードバランサへのアクセスを制限する方法については、クラウド プロバイダのファイアウォールの構成をご覧ください。Service の仕様の詳細については、Service API リファレンスをご覧ください。

すべてのポートの使用

アノテーション付きの Service を使用して TCP / UDP ロードバランサを作成する場合、すべてのポートを使用する転送ルールを設定する方法はありません。ただし、内部 TCP / UDP ロードバランサを手動で作成する場合は、バックエンドとして Google Kubernetes Engine ノードのインスタンス グループを選択できます。type: NodePort の Kubernetes Services は ILB 経由で使用できます。

内部 TCP / UDP ロードバランサの制限事項

  • Kubernetes バージョン 1.7.3 以前を実行しているクラスタの場合、自動モードのサブネットでのみ内部 TCP / UDP ロードバランサを使用できます。Kubernetes バージョン 1.7.4 以降の場合は、自動モードのサブネットだけでなく、カスタムモードのサブネットでも内部ロードバランサを使用できます。
  • Kubernetes 1.7.X 以降を実行しているクラスタの場合、clusterIP が変更されないため、内部 TCP / UDP ロードバランサは予約済みの IP アドレスを使用できません。spec.loadBalancerIP フィールドに未使用の IP アドレスを定義し、特定の内部 IP を割り当てることができます。ポート、プロトコル、セッション アフィニティを変更すると、IP アドレスが変更されることがあります。

内部 UDP ロードバランサの制限事項

  • 内部 UDP ロードバランサは、sessionAffinity: ClientIP の使用をサポートしていません。

上限

type: Loadbalancer の Kubernetes Service と cloud.google.com/load-balancer-type: Internal アノテーションを使用すると、Kubernetes Service を対象にする ILB が作成されます。このような Service の数は、VPC ネットワークで作成できる内部転送ルールの数によって制限されます。詳細については、ネットワークごとの制限をご覧ください。

GKE クラスタでは、内部転送ルールはクラスタ内のすべてのノードを参照します。クラスタの各ノードは ILB のバックエンド VM になります。VM がインスタンス グループに関連付けられる方法に関係なく、ILB のバックエンド VM の最大数は 250 です。したがって、ILB 内 GKE クラスタの最大ノード数は 250 になります。クラスタで自動スケーリングが有効になっている場合、自動スケーリングでクラスタのノード数が 250 を超えないようにする必要があります。

これらの制限事項の詳細については、VPC リソースの割り当てをご覧ください。

次のステップ

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

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

Kubernetes Engine のドキュメント