Kubernetes 解体新書Part 2 ネットワーク

LB から Pod へ直接送る

ロードバランサーから Pod へ直接送るには何が必要でしょうか。AWS と Google Cloud の構成で確かめます。

  • L0 ブラウザだけ
  • 更新 2026年10月6日

第 6 章で見た経路では、ロードバランサーがノードへ送り、そのノードが Pod へ転送していました。 最初からロードバランサーが Pod に送れれば、この転送を 1 段減らせます。

そのためには、Pod の IP まで通信が届くことと、動いている Pod をロードバランサーに知らせることが必要です。 AWS と Google Cloud では、この 2 つをどう実現しているのかを見ていきます。

GOAL この章のゴール

  • ロードバランサーがノードへ送る構成と、Pod へ送る構成を区別できる
  • Pod へ直接送るために必要な条件を説明できる
  • AWS と Google Cloud で、その条件を満たす仕組みが分かる

ノードを経由する構成の回り道

第 6 章の経路をもう一度見ます。 ELB のターゲットは「全ノードの NodePort」でした。 この構成では、ELB にノード (10.0.1.11 など) を送り先として登録しています。 Pod の IP に直接届く経路や登録の仕組みを用意していないため、ノードを経由して送ります。

標準の type: LoadBalancer では、LB はノードしか知らない。Pod の無いノードに届くと、もう 1 ホップ増えるLB のターゲットは 3 台のノードの NodePort。Pod は Node 2 にしか無いのに、LB は Node 1 や Node 3 にも均等に送り、そこから Node 2 へ転送される。ELBターゲット = ノードNode 110.0.1.10:30080web の Pod は無いNode 210.0.1.11:30080web10.244.2.7Node 310.0.1.12:30080web の Pod は無い1/31/31/3余計なホップ (SNAT)余計なホップ (SNAT)LB は Pod の所在を知らないので、2/3 の通信が遠回りする
図 1ELB は 3 台のノードに均等に送る。Pod は Node 2 にしか無いので、2/3 の通信は別ノードを経由して SNAT 付きで転送される。

GKE のドキュメントは、この構成の問題を次のように列挙しています。 「ロードバランサーから VM の NodePort へ、そこから kube-proxy の経路で Pod IP へ (別の VM に居るかもしれない) という 2 ホップの負荷分散になり、レイテンシが増え経路が複雑になる」、「ロードバランサーは Pod を直接見られないので負荷分散が最適にならない」、「VM や Pod の消失が、2 ホップのせいで一時的な通信の欠落を起こしやすい」。 externalTrafficPolicy: Local (第 6 章) はヘルスチェックで Pod の無いノードを外す対症療法で、LB が見ているのがノードであることは変わらず、Pod 数がノード間で偏れば負荷も偏ります。

LB のターゲットを Pod にする

理想は、LB が Pod の所在を知っていて、ClusterIP も NodePort も介さず Pod に直接送ることです。

コンテナネイティブ LB: Pod が VPC のアドレスを持てば、LB のターゲットを Pod にできるPod の IP が VPC のルーティング可能なアドレスなので、LB のターゲットグループに Pod IP を直接登録できる。NodePort も SNAT も経由せず、LB から Pod へ 1 ホップで届く。ALB / NLBターゲット = Pod IPVPC 10.0.0.0/16 (Pod も同じアドレス空間)Node 110.0.1.10web10.0.1.23Node 210.0.1.11web10.0.1.57Node 310.0.1.12web の Pod は無い(ターゲットに入らない)直接LB が Pod の所在と健康状態を知っている。NodePort も SNAT も通らない
図 2Pod が VPC のアドレスを持てば、LB のターゲットグループに Pod IP を登録できる。NodePort も SNAT も通らず 1 ホップ。

これが成り立つ条件は 1 つで、Pod の IP が VPC から直接届くアドレスであること です。 VXLAN で包む構成では、Pod の IP は VPC のルートテーブルに載らないので、LB はそこへ送れません。 第 4 章で見たとおり、CNI プラグインの仕事には「Pod の IP を配る (IPAM)」と「ノード間の疎通を担保する」があり、両方を VPC に任せる CNI プラグインなら、Pod は VPC のアドレスを持ちます。

コンテナネイティブ・ロードバランシング とは、GKE のドキュメントの定義では「Pod のエンドポイントに直接負荷分散すること」で、こうして LB のターゲットをノードから Pod に変えた構成を指します。 公式ドキュメントの Service の説明にも、Pod へ直接送る LB 実装のために NodePort の割り当てを止める allocateLoadBalancerNodePorts: false という設定があります。

AWS での実装

AWS での実装: VPC CNI が Pod に VPC アドレスを配り、AWS Load Balancer Controller が Pod IP をターゲットグループに登録するVPC CNI の ipamd が ENI のセカンダリ IP を Pod に渡す。AWS Load Balancer Controller が EndpointSlice を watch し、ALB / NLB のターゲットグループ (target-type: ip) に Pod IP を登録・削除する。AWS Load Balancer ControllerIngress / Service /Gateway API を watchEndpointSlice の Pod IP をターゲットグループに同期ALB / NLBtarget-type: ipRegisterTargetsターゲットグループ10.0.1.23:8080 healthy10.0.1.57:8080 healthy10.0.2.14:8080 drainingVPC サブネット 10.0.1.0/24EC2 ノードENI eth1: .20〜.29ipamd (aws-node) が管理web10.0.1.23web10.0.1.57secondary IPALB は L7 (HTTP)NLB は L4 (TCP / UDP)
図 3VPC CNI が ENI のセカンダリ IP を Pod に配り、AWS Load Balancer Controller が Pod IP をターゲットグループに登録する。

AWS では 2 つの部品で実現します。

  1. Amazon VPC CNI:第 4 章で見たとおり、ノードの ENI に付いたセカンダリ IP を Pod に渡します。AWS のドキュメントの言い方では「Pod は VPC ネットワーク上と同じ IP アドレスを持つ」ので、VPC から Pod に直接届きます。
  2. AWS Load Balancer Controller:Ingress から ALB (L7) を、Service から NLB (L4) を、Gateway API からその両方を作るコントローラーです。ターゲットの種類は instance と ip の 2 つで、ドキュメントは ip モードを「ALB から Kubernetes の Pod に直接届く。CNI が ENI のセカンダリ IP で Pod に直接到達できる必要がある」、instance モードを「ALB から各 Service の NodePort 経由でノードに届く」と説明しています。IP ターゲットでは EndpointSlice から Pod の IP を集めて登録し、Pod の増減に追従します。

ターゲットグループの中身がノードの IP か Pod の IP かを見れば、どちらの構成かすぐ分かります。 ip モードにすると、Pod の readiness gate (elbv2.k8s.aws/pod-readiness-gate-inject) で、ターゲットグループ側で healthy になるまで Pod を Ready にしない仕組みも使えます。 ローリングアップデートで新しい Pod が LB から見て準備できる前に古い Pod が消える問題を防ぐための機能で、ドキュメントは「instance モードではノードが backend なので使えない」と書いています。

GCP での実装

GCP での実装: VPC-native クラスタの alias IP で Pod が VPC アドレスを持ち、NEG が Pod を LB のバックエンドにするVPC-native クラスタでは Pod CIDR がサブネットのセカンダリ範囲 (alias IP) になる。NEG controller が Service の Pod を Network Endpoint Group に登録し、Cloud Load Balancing は NEG を直接バックエンドにする。Cloud Load Balancingbackend = NEGNEG (GCE_VM_IP_PORT)10.8.0.5:808010.8.1.9:8080readiness gate で健康状態を同期NEG controllerService の annotationcloud.google.com/negを見て NEG に Pod を登録VPC サブネット: primary 10.0.1.0/24 / secondary (alias) 10.8.0.0/14 = Pod CIDRノード 10.0.1.10alias range 10.8.0.0/24VPC がこの範囲を知っているweb10.8.0.5web10.8.1.9Pod は alias IP を持ちVPC から直接届く
図 4VPC-native クラスタでは Pod CIDR がサブネットの alias IP 範囲になり、NEG controller が Pod を Network Endpoint Group に登録する。

GKE では、クラスタを VPC-native で作ると、サブネットのセカンダリ範囲 (alias IP) が Pod の IP 範囲になります。 GKE のドキュメントによれば、各ノードは /24 の alias IP 範囲を 1 つ持ち、その範囲から Pod に IP を配り、「Pod の IP はクラスタの VPC ネットワーク内でネイティブにルーティングできる」ので、静的ルートに依存しません。 VPC-native は新しいクラスタの既定です。

LB 側は NEG (Network Endpoint Group) を使います。 GKE のドキュメントの定義では、コンテナネイティブ LB は「GCE_VM_IP_PORT 型の NEG を使い、そのエンドポイントは Pod の IP アドレス」です。 Service に cloud.google.com/neg: '{"ingress": true}' の annotation が付くと NEG が作られ、Cloud Load Balancing は NEG をバックエンドにします。 ドキュメントは「コンテナネイティブ LB が無いと、通信はノードのインスタンスグループへ送られ、kube-proxy が設定した iptables ルールで Pod へ転送される。コンテナネイティブ LB では Pod に直接負荷分散され、VM の IP と kube-proxy を経由しない」と説明し、Pod の readiness gate で LB から見た健康状態を判定する点も利点に挙げています。

コンテナネイティブ LB の 2 つの実装
観点AWSGCP
Pod の IPVPC CNI が ENI のセカンダリ IP を配るVPC-native の alias IP 範囲 (ノードごとに /24) から配る
LB のターゲットターゲットグループ (target-type: ip)NEG (GCE_VM_IP_PORT)
登録するコントローラーAWS Load Balancer ControllerGKE 組み込みの NEG controller
Pod 数の上限インスタンスタイプの ENI 数 × IP 数ノードの alias 範囲のサイズ

オンプレではどうなのか

オンプレでは、Pod の IP を物理ネットワークから直接届くアドレスにする必要があります。 技術的には、第 4 章の BGP で Pod CIDR を物理ルーターに教えれば (Calico や Cilium)、外部の LB のターゲットに Pod IP を登録できます。 ただし物理網の設定変更が要るので、クラウドほど手軽ではありません。

ふりかえり

Q標準の type: LoadBalancer で余計なホップが生じる根本の理由は?

Node ネットワークと Pod ネットワークが分断されているので、LB はノードにしか送れません。受けたノードが Pod の所在を引いて転送するため、Pod の無いノードに届いた分が遠回りします。

Qコンテナネイティブ LB が成り立つための条件は?

LB のターゲットに Pod IP を登録するには、VPC のルーティングでその IP に届く必要があります。VPC CNI の ENI セカンダリ IP や GKE の alias IP がそれを満たします。

QAWS で Pod IP をターゲットグループに登録しているのは?

AWS Load Balancer Controller が EndpointSlice を読み、target-type: ip のターゲットグループに Pod IP を登録し、消えれば外します。cloud-controller-manager の Service controller が作る CLB / NLB はノードをターゲットにする従来方式です。

参考