Pod 同士が通信する仕組み

v1.37 時点(2026年10月25日 確認)

Kubernetes 基本仕様第20回 / 全45回 ・ 第4部 ネットワーク
目次

この記事ではクラスタの中で Pod どうしがどう通信できるべきかを決めた Kubernetes のネットワークモデル の仕組みを、図で説明します。Pod ごとに IP アドレスが付くこと、ノードが違っても Pod どうしがアドレスの変換(NAT)なしで直接通信できること、その通信を誰が用意しているのかがわかります。後半では kind のマルチノードのクラスタで、別のノードの Pod に IP アドレスで直接届くことを確かめる手順を示します。

この回から第4部(ネットワーク)に入ります。Pod の中のコンテナがネットワークを共有することを扱った第8回の内容を前提にしています。まだの方は先にこちらをどうぞ。

基本仕様 ・ 第8回 Pod を動かして理解するKubernetes で作って管理できる最小の単位である Pod の仕組みを図で説明します。Pod とコンテナの関係、Pod の中のコンテナが共有するもの、Pod が 1 つのノードに置かれて移らないことを押さえ、kind のクラスタで Pod を直接作って削除し、もう戻らないことを確かめる手順を紹介します。

以下の図は kind のマルチノードのクラスタで、2 つのワーカーのノードに置いた Pod が、相手の Pod の IP アドレスで通信する様子を表しています。後半の「手元で試す」で作る状態にあたります。

ノードをまたいで、相手の Pod の IP アドレスで通信する Pod(コントロールプレーンのノードは省略)

IP アドレスは Pod ごとに付きます。client の Pod は同じノードの nginx の Pod にも、別のノードの nginx の Pod にも、相手の Pod の IP アドレスを宛先にして届きます。ノード 2 の枠に向かう線も、宛先はノードではなく枠の中の nginx の Pod の IP アドレスです。公式ドキュメントのネットワークモデルは、同じノードでも違うノードでも、すべての Pod がほかのすべての Pod と通信できることを求めています。それも、通信を中継するもの(プロキシ)やアドレスの変換(NAT)を使わずに、直接通信できることです。NAT は後で説明します。コントロールプレーンのノードは図から省きました。第15回で見たとおり、コントロールプレーンのノードの Taint を許容しない Pod は、そのノードには置かれないからです。

参考:Services, Load Balancing, and Networking | Kubernetes、Pods | Kubernetes、Taints and Tolerations | Kubernetes

Kubernetes のネットワークモデルとは

説明に入る前に、IP アドレスを確かめておきます。一般に、IP アドレスはネットワークの中で通信の相手を見分けるための番号です。手紙の宛先の住所のようなもので、通信するときは相手の IP アドレスを宛先にします。第8回で見たとおり、IP アドレスには 10.88.0.3 のような IPv4 と、2001:db8::1 のような IPv6 の形式があります。

Kubernetes のネットワークモデル(the Kubernetes network model)は、クラスタの中の Pod どうしがどのように通信できるべきかを定めた決まり です。公式ドキュメントは、ネットワークモデルがいくつかの部品でできていると説明しています。そのうち Pod にかかわる部分を次の表にまとめます。右の列は公式ドキュメントの文に沿った訳です。

項目公式ドキュメントの説明
Pod の IP アドレスクラスタの各 Pod は、クラスタ全体で一意な、自分の IP アドレスを持つ
Pod のネットワークの namespacePod は自分専用のネットワークの namespace を持ち、Pod の中のすべてのコンテナがそれを共有する。同じ Pod の別々のコンテナで動くプロセスは、localhost で互いに通信できる
Pod どうしの通信すべての Pod は、同じノードにいても違うノードにいても、ほかのすべての Pod と通信できる。Pod どうしは、プロキシやアドレスの変換(NAT)を使わずに直接通信できる
ノードの上のエージェントと Pod の通信ノードの上のエージェント(システムのデーモンや kubelet など)は、そのノードのすべての Pod と通信できる

参考:Services, Load Balancing, and Networking | Kubernetes

ネットワークの namespace は、第8回で名前だけ紹介した Linux の namespace の 1 つです。Kubernetes の Namespace(第3回)とは別のものです。Pods のページも、Pod にはアドレスの種類(IPv4 や IPv6)ごとに一意の IP アドレスが付き、Pod の中のすべてのコンテナが IP アドレスとポートを含むネットワークの namespace を共有する、と説明しています。

参考:Pods | Kubernetes

表の下の 2 行は、公式ドキュメントが Pod のネットワーク(pod network。クラスタのネットワーク、cluster network とも呼ぶ)の役割として挙げているものです。Pod のネットワークは Pod どうしの通信を受け持ち、意図してネットワークを区切っていない限り(barring intentional network segmentation)、この 2 つを保証します。Windows には例外があります(「注意点」の節の最後で説明します)。Pod どうしの通信を制御する API として NetworkPolicy があり、第25回で扱います。

参考:Services, Load Balancing, and Networking | Kubernetes

表に出てきた NAT は Network Address Translation(アドレスの変換)の略です。一般に、ネットワークを流れるデータはパケットという小さなまとまりに分けて送られます。公式のチュートリアルはパケットの送り元の IP アドレスを書き換えることを Source NAT、宛先の IP アドレスを書き換えることを Destination NAT と説明しています。一般に NAT は、たとえば複数の機器が 1 つのアドレスを共有して外のネットワークとやり取りするときなどに使われます。ネットワークモデルは、Pod どうしがこうした書き換えをされずに、直接通信できることを求めています。書き換えが無いので、通信を受け取った Pod から見える送り元の IP アドレスは、送った Pod の IP アドレスのままのはずです。

参考:Using Source IP | Kubernetes、Services, Load Balancing, and Networking | Kubernetes

API リファレンスも Pod の status.podIP(第5回)を「少なくともクラスタの中ではルーティングできる(Routable at least within the cluster)」アドレスと説明しています。ルーティングできるとは一般に、宛先のアドレスまでデータを届けられるということです。

参考:Pod | Kubernetes API Reference

ネットワークモデルにはこのほかに Service、Gateway API(とその前身の Ingress)、NetworkPolicy の部品があります。Service は Pod の集まりに変わらない IP アドレスや名前を与える API、Gateway API と Ingress はクラスタの外のクライアントから Service に届くようにする API です。それぞれ第21回、第24回、第25回で扱います。

参考:Services, Load Balancing, and Networking | Kubernetes

なぜ Kubernetes のネットワークモデルが必要なのか

公式ドキュメントの Cluster Networking のページは、Kubernetes はアプリケーションどうしでマシンを共有するためのもの、と説明しています。マシンを共有すると、ふつうは 2 つのアプリケーションが同じポートを使おうとしないようにする必要があります。第8回で見たとおり、ポートは 1 つの IP アドレスの中で通信の相手のプログラムを見分ける番号です。公式ドキュメントによると、大きな規模で、多くの開発者のあいだでポートの使い方を調整するのはとても難しく、利用者にはどうにもできないクラスタの問題も招きます。

参考:Cluster Networking | Kubernetes

ポートを動的に割り当てる方法もありますが、公式ドキュメントは、それにも多くの面倒があると説明しています。アプリケーションはどれも使うポートを引数で受け取る必要があります。API サーバー(原文は the API servers)は、動的に決まったポートの番号を設定の中に書き込む方法を知っている必要があります。サービスどうしは互いを見つける方法を持つ必要があります。Kubernetes はこうした面倒を引き受けずに、別のやり方をとる、としています。ページはその続きで、ネットワークモデルの説明へ案内しています。

参考:Cluster Networking | Kubernetes

公式ドキュメントは古いコンテナのシステムとの違いも説明しています。古いシステムでは、別々のホスト(コンテナを動かすマシン)のコンテナどうしが自動ではつながりませんでした。そのため、コンテナどうしのつながりを明示的に作ったり、コンテナのポートをホストのポートに対応付けて、ほかのホストのコンテナから届くようにしたりする必要がよくありました。対応付けとは一般的な例でいえば「ホストの 8080 番に届いた通信を、コンテナの 80 番へ回す」という対応を、自分で書くことです。Kubernetes ではこうした作業が要りません。ポートの割り当て、名前の付け方、サービスの見つけ方、負荷の分散、アプリケーションの設定、移行といった点で、Pod を仮想マシン(VM)や物理的なホストとほとんど同じように扱える、というのが Kubernetes のモデルです。

参考:Services, Load Balancing, and Networking | Kubernetes

公式のチュートリアルも nginx の Pod を 2 つ動かした例で同じことを説明しています。コンテナはノードの 80 番のポートを使っておらず、Pod に通信を届けるための特別な NAT の決まりもありません。そのため、同じ containerPort を使う nginx の Pod を同じノードにいくつも動かせます。どの Pod にも、クラスタのほかの Pod やノードから、その Pod に割り当てられた IP アドレスで届きます。

参考:Connecting Applications with Services | Kubernetes

まとめると、IP アドレスが Pod ごとにあるので、別々の Pod は同じポートの番号を使えます。Pod が自分のネットワークの namespace を持つふつうの場合、ポートの番号を譲り合う必要があるのは、IP アドレスとポートを共有する同じ Pod の中のコンテナどうしです(第8回)。ホストのネットワークを使う Pod は例外で、「注意点」の節の最後で触れます。

参考:Connecting Applications with Services | Kubernetes、Pods | Kubernetes

Kubernetes のネットワークモデルの仕組み

4 種類の通信とこの回で扱う範囲

Cluster Networking のページは、ネットワークで解決すべき問題を次の 4 つに分けています。

通信公式ドキュメントでの扱い
密に結び付いたコンテナどうしPod と、localhost での通信で解決する(第8回、第10回)
Pod どうしCluster Networking のページの主題(この回)
Pod から Service へService で扱う(第21回)
クラスタの外から Service へこれも Service で扱う(第22回)

参考:Cluster Networking | Kubernetes

第10回では、サイドカーが localhost:80 で同じ Pod の nginx に問い合わせました。Pods のページは、Pod の中で(そして Pod の中だけで)、Pod に属するコンテナは localhost で互いに通信できる、と説明しています。別の Pod のコンテナは IP アドレスが別なので、IP のネットワークで通信します。この回で扱うのは、この Pod どうしの通信です。

参考:Pods | Kubernetes、Cluster Networking | Kubernetes

Kubernetes はコンテナランタイムに、Pod のサンドボックスなど、サンドボックスごとにループバックのインターフェース lo を用意することも求めています。Pod のサンドボックスは原文では pod sandboxes で、Pod のための隔てられた環境と読めます。一般に、ループバックは自分自身に戻ってくる通信の口で、localhost はそのアドレスを指す名前です。同じ Pod のコンテナどうしが localhost で届くのは、Pod のネットワークの namespace を共有していて、その中にこの lo があるからだと考えられます。

参考:Network Plugins | Kubernetes、Pods | Kubernetes

誰が Pod のネットワークを用意するのか

この節からは似た言葉がいくつか出てきます。公式ドキュメントでの言い方と、この記事での呼び方を次の表にまとめます。

言葉指すもの
ネットワークモデルPod どうしなどがどう通信できるべきかの決まり
Pod のネットワーク(クラスタのネットワーク)ネットワークモデルの部品のうち、Pod どうしの通信を受け持つもの
Pod のネットワークの実装、ネットワークプラグイン、CNI プラグインPod のネットワークを実際に用意するソフトウェア。公式ドキュメントはページによってこれらの言い方を使う。この記事ではネットワークプラグインと呼ぶ
Pod のネットワークのアドオンkubeadm の公式ドキュメントでの言い方。クラスタを作ったあとに入れる、CNI を使うネットワークプラグインを指す
ネットワークの namespacePod ごとのネットワークの環境(Linux の仕組み)。コンテナランタイムが用意する

参考:Services, Load Balancing, and Networking | Kubernetes、Cluster Networking | Kubernetes、Network Plugins | Kubernetes、Creating a cluster with kubeadm | Kubernetes

公式ドキュメントによると、ネットワークモデルのうち Kubernetes 自身が実装しているのは、ほんの一部です。ほかの部分は、Kubernetes が API を決め、対応する機能は外部のコンポーネントが提供します。省略できるコンポーネントもあります。Pod にかかわる部分の受け持ちを、次の表にまとめます。

部分受け持つもの
Pod のネットワークの namespace の用意CRI を実装した、システムのソフトウェア(コンテナランタイム。第4回)
Pod のネットワークそのものPod のネットワークの実装(ネットワークプラグイン)。Linux では、ほとんどのコンテナランタイムが CNI でこの実装とやり取りするので、CNI プラグインと呼ばれることが多い
Service への通信の中継既定の実装は kube-proxy。代わりに自分の仕組みで中継するネットワークプラグインもある(第21回)
NetworkPolicyふつうはネットワークプラグインが受け持つ。実装していない場合、API はあっても効果がない(第25回)

参考:Services, Load Balancing, and Networking | Kubernetes

第4回ではネットワークプラグインを、CNI という仕様を実装したソフトウェアとして紹介しました。CNI(Container Network Interface)プラグインは、CNI の仕様に沿ったネットワークプラグインです。公式ドキュメントによると、ネットワークモデルを実装するには CNI プラグインが必要です。使う CNI プラグインはクラスタに合っていて、目的にもかなうものである必要があります。対応する CNI の仕様のバージョンは、v1.37 時点では v0.4.0 以降が必要で、v1.0.0 が勧められています。

参考:Network Plugins | Kubernetes、Network Plugins | Kubernetes

CNI プラグインを読み込むのはコンテナランタイムです。公式ドキュメントによると、コンテナランタイムは、ネットワークモデルの実装に必要な CNI プラグインを読み込むように設定されている必要があります。v1.24 からは、CNI の管理は kubelet の役目ではありません。Cluster Networking のページも、ネットワークモデルは各ノードのコンテナランタイムが実装し、よく使われるコンテナランタイムは CNI プラグインでネットワークを管理する、と説明しています。

参考:Network Plugins | Kubernetes、Cluster Networking | Kubernetes

以下の図は 1 つのノードの中で、Pod のネットワークを用意するコンポーネントの受け持ちを表しています。

ノードの中で Pod のネットワークを用意するコンポーネントの受け持ち

kubelet は CRI でコンテナランタイムに Pod を動かしてもらいます(第4回)。そのコンテナランタイムが Pod のネットワークの namespace を用意し、CNI でネットワークプラグインとやり取りします。Pod に IP アドレスを割り当てるのはネットワークプラグインです(次の節)。図の実線はやり取り(指示や CNI での呼び出し)、破線は用意する・割り当てる関係を表します。kind では、ネットワークプラグインの箱は kindnetd と、同梱の標準の CNI プラグイン(ptp、host-local など)をまとめて表したものと考えられます。

図は受け持ちだけを表したもので、ネットワークプラグインが Pod どうしをどうつなぐか(データの通り道の作り方など)は描いていません。公式ドキュメントによると、CNI プラグインには多くの種類があり、ネットワークのインターフェース(ネットワークにつながる口)を足したり外したりする基本の機能だけを持つものも、もっと高度な機能を持つものもあります。Kubernetes が決めているのはネットワークモデルの要件と API で、Pod のネットワークそのものはネットワークプラグインが提供します。

参考:Container Runtime Interface (CRI) | Kubernetes、Configuration | kind、Services, Load Balancing, and Networking | Kubernetes、Cluster Networking | Kubernetes

ネットワークプラグインは Kubernetes 本体には含まれません。第2回で見たとおり、kubeadm でクラスタを作ったあとは、Pod どうしが通信できるように、CNI を使う Pod のネットワークのアドオンを入れる必要があります。kubeadm の公式ドキュメントによると、ネットワークを入れるまでクラスタ DNS(CoreDNS)は起動しません。1 つのクラスタに入れられる Pod のネットワークは 1 つだけです。kind はクラスタを作るときに、これを kindnetd で済ませています(後で説明します)。

参考:Creating a cluster with kubeadm | Kubernetes、Configuration | kind

Pod の IP アドレスの範囲

公式ドキュメントによると、クラスタでは Pod、Service、ノードに、重ならない IP アドレスを割り当てる必要があります。割り当てる IP アドレスは次のコンポーネントに設定した範囲から選ばれます。

割り当てる相手割り当てるように設定するもの
Podネットワークプラグイン
Servicekube-apiserver
ノードkubelet か cloud-controller-manager(クラウドの環境とつなぐコンポーネント)

参考:Cluster Networking | Kubernetes

IP アドレスの範囲は 10.244.0.0/16 のような形で書きます。一般に、この書き方を CIDR(読み:サイダー)表記と呼びます。/ の後ろの数は、IP アドレスの先頭から何ビット(2 進数の桁)が共通かを表します。IPv4 のアドレスは 0〜255 の 4 つの数を . でつないだもので、1 つの数が 8 ビットです。そのため /16 は先頭の 2 つの数、/24 は先頭の 3 つの数が共通な範囲になります。10.244.0.0/16 なら、先頭の 10.244 が共通な IP アドレスの範囲です。数が大きいほど、範囲は狭くなります。

kind の公式ドキュメント(kind v0.33.0 時点)によると、kind は既定では、Pod の範囲に IPv4 では 10.244.0.0/16、IPv6 では fd00:10:244::/56 を使います。Service の範囲は IPv4 では 10.96.0.0/16、IPv6 では fd00:10:96::/112 です。どちらもクラスタの設定ファイルの networking の podSubnet と serviceSubnet で変えられます。アドレスの種類(ipFamily)の既定は ipv4 で、ipv6 や、両方を使う dual にもできます。この回のクラスタは既定のままなので、Pod の IP アドレスは IPv4 の 1 つだけのはずです。

参考:Configuration | kind、Configuration | kind、Configuration | kind

kubeadm で作ったクラスタでは、クラスタの Pod の範囲の一部を、コントロールプレーンがノードごとに割り当てることがあります。kubeadm の公式ドキュメントによると、kubeadm init に Pod のネットワークの範囲(--pod-network-cidr)を指定すると、コントロールプレーンがすべてのノードに CIDR を自動で割り当てます。kind のクラスタもそうなっているかは、後半の「手元で試す」で確かめます。

参考:kubeadm init | Kubernetes

ノードに割り当てた範囲は Node の spec.podCIDR というフィールドに表れます。API リファレンスはこのフィールドを「ノードに割り当てられた、Pod の IP アドレスの範囲」と説明しています。spec.podCIDRs はその一覧で、IPv4 と IPv6 のそれぞれに多くても 1 つです。公式ドキュメントはこの割り当てを、一部の CNI プラグインが必要とする機能(the subnet manager feature required for some CNI network plugins)と説明しています。ノードごとの範囲を使うかどうかは、ネットワークプラグインによって違うと読めます。

参考:Node | Kubernetes API Reference、Implementation details | Kubernetes

kind の公式ドキュメントには、ノードごとの範囲の説明はありません。kind v0.33.0 のソースコードでは、設定の podSubnet の値を、kubeadm の設定ファイルの networking.podSubnet(kubeadm のリファレンスの説明は「Pod が使う範囲」)に渡しています。これが --pod-network-cidr を指定したときと同じように働くなら、kind のクラスタのノードにも spec.podCIDR が入っていると考えられます。後半の「手元で試す」で確かめます。

参考:kind のソースコード(kubeadm の設定)、kubeadm Configuration (v1beta4) | Kubernetes

以下の図は、kube-controller-manager がクラスタの Pod の範囲をノードごとの範囲に分けて割り当てる場合の、2 つの範囲の関係を表しています。

ノードごとの範囲を割り当てる場合の、クラスタの Pod の範囲とノードごとの範囲(spec.podCIDR)

図のノードのアイコンは各ノードに割り当てた範囲(spec.podCIDR)を表していて、ノード自身の IP アドレスがこの範囲から付くという意味ではありません。ノードごとの範囲はクラスタの Pod の範囲の一部で、ノードどうしで重ならないように割り当てられると考えられます。図は kube-controller-manager がノードに範囲を割り当てるところまでを表したものです。Pod の IP アドレスをノードの範囲から選ぶかどうかは、ネットワークプラグインによって違うと考えられるため、図には Pod を描いていません。破線は、これまでの回の図と同じく、管理する関係を表します。

参考:Cluster Networking | Kubernetes、Nodes | Kubernetes、Implementation details | Kubernetes

Pod の IP アドレスは Pod の status の 2 つのフィールドに入ります。API リファレンスの説明を次の表にまとめます。

フィールド内容
status.podIPPod に割り当てられた IP アドレス。少なくともクラスタの中ではルーティングできる。まだ割り当てられていなければ空
status.podIPsPod に割り当てられた IP アドレスの一覧。先頭の項目は status.podIP と同じ。IPv4 と IPv6 のそれぞれに多くても 1 つ

参考:Pod | Kubernetes API Reference

IPv4 と IPv6 の両方を使う構成(デュアルスタック)は、v1.23 から安定版(Stable)の機能です。公式ドキュメントによると、デュアルスタックでは Pod に IPv4 と IPv6 のアドレスが 1 つずつ割り当てられます。使うには、デュアルスタックに対応したネットワークプラグインが要ります。Cluster Networking のページも、デュアルスタックではネットワークプラグイン、kube-apiserver、kubelet(または cloud-controller-manager)がどれも IPv4 と IPv6 のアドレスを割り当てるように設定され、主に使うアドレスの種類をそろえる必要がある、と説明しています。

参考:IPv4/IPv6 dual-stack | Kubernetes、IPv4/IPv6 dual-stack | Kubernetes、Cluster Networking | Kubernetes

Pod の IP アドレスは Pod と一緒に変わる

IP アドレスは Pod に付くので、Pod が入れ替わると IP アドレスも変わり得ます。Service のページは、Pod は作られては消える、長くは続かないリソース(ephemeral resources)で、1 つの Pod が頼りになり、長く続くとは考えないほうがよい、と説明しています。続けて、Pod にはそれぞれの IP アドレスが付く(Kubernetes はネットワークプラグインがこれを保証することを期待している)が、Deployment の Pod の顔ぶれはある瞬間と次の瞬間とで違うことがある、としています。

参考:Service | Kubernetes

公式のチュートリアルも、ノードが止まると Pod も一緒に止まり、Deployment の中の ReplicaSet が新しい Pod を作るが、その Pod は別の IP アドレスになる、と説明しています。第14回でも、StatefulSet の Pod を作り直すと IP アドレスが変わることがある、と見ました。そのため、相手の Pod の IP アドレスを書き込んで使い続けると、相手が作り直されたときに届かなくなると考えられます。チュートリアルは、これが Service で解決する問題だとしています。Service は第21回、名前で相手を指す DNS は第23回で扱います。

参考:Connecting Applications with Services | Kubernetes、StatefulSet Basics | Kubernetes

kind のクラスタのネットワークプラグイン

kind の公式ドキュメントによると、kind には、標準の CNI プラグイン(ptp、host-local など)と、単純な経路の設定(simple netlink routes)でできた、簡単なネットワークの実装(kindnetd)が同梱されています。それぞれの部品がどう働くかは kind の公式ドキュメントに書かれていないため、この回では立ち入りません。kind の公式ドキュメントは、kindnetd が IP マスカレード(一般に、送り元の IP アドレスを別のアドレスに書き換える NAT の一種)も扱う、としています。ネットワークモデルの「NAT なし」は Pod どうしの通信についての決まりなので、Pod からクラスタの外へ出る通信で送り元が書き換えられることとは別の話だと考えられます。

参考:Configuration | kind

第4回と第15回で見たとおり、kind のクラスタの kube-system では、kindnetd が kindnet という名前の DaemonSet として、ノードごとに 1 つずつ動いています(kind v0.33.0 のソースコードで確かめた名前です)。公式ドキュメントも、ネットワークプラグインには DaemonSet として動く部品が含まれることが多く、その部品が、動いているノードでクラスタのネットワークが働くようにする、と説明しています。

参考:kind のソースコード(kindnet)、DaemonSet | Kubernetes

kind の設定ファイルで networking の disableDefaultCNI を true にすると、kindnetd は入りません。ほかのネットワークプラグインを入れたいときに使う設定です。kind の公式ドキュメントは、これは慣れた人向けの機能でサポートは限られるが、Calico などよく使われる CNI のマニフェストの多くは動くことがわかっている、としています。Kubernetes の公式ドキュメントにも、ネットワークのアドオンの一覧(すべてではない)があります。

参考:Configuration | kind、Installing Addons | Kubernetes

手元で試す

ここまでの内容を手元の kind のクラスタで試す手順を示します。ノードごとの Pod の IP アドレスの範囲を見たあと、2 つのワーカーのノードに nginx の Pod を 1 つずつ置き、通信元の Pod を作ります。通信元の Pod から、同じノードの nginx の Pod と、別のノードの nginx の Pod に、IP アドレスで直接届くことを確かめます。続けて、localhost では別の Pod に届かないことを確かめ、Pod を作り直して IP アドレスを見比べます。コマンドは macOS や Linux のシェル(bash や zsh)で実行する前提で書いています。Windows では WSL(Windows の中で Linux を動かす仕組み)などを使ってください。試す環境は次のとおりです。

項目内容
kindv0.33.0
Kubernetesv1.37.0(kind v0.33.0 の既定のノードイメージ)
ノード構成マルチノード(クラスタ名 multi-node):コントロールプレーン 1、ワーカー 2
必要なものDocker、kubectl(v1.36〜v1.38)、テキストエディタ、端末(ターミナル)2 つ

参考:Release v0.33.0 · kubernetes-sigs/kind、Version Skew Policy | Kubernetes

kind でクラスタを作る手順は、以下の記事で解説しています。この回は第2回〜第4回、第15回と同じマルチノードのクラスタを使います。ノードをまたいだ通信は、ノードが 1 つでは試せないからです。

基本仕様 ・ 第2回 kind で検証用のクラスタを作るDocker のコンテナをノードにして、手元のマシンに Kubernetes のクラスタを作るツール kind の仕組みを図で説明します。kind create cluster で何が起きるかを押さえ、シングルノードとマルチノードのクラスタを作って、ノードの正体が Docker のコンテナであることを確かめる手順を紹介します。

マルチノードのクラスタを用意する

第2回と同じ次の設定ファイルを使います。公式ドキュメントの例をそのまま引用しています。kind-multi-node.yaml という名前で、コマンドを実行するディレクトリに保存します。第2回〜第4回や第15回で保存したファイルが残っていれば、それを使えます。

yaml
# three node (two workers) cluster config
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker

参考:Quick Start | kind

この設定ファイルには networking を書いていないので、Pod の範囲(podSubnet)やアドレスの種類(ipFamily)は kind の既定のままです。

参考:Configuration | kind

まず、前の回のクラスタが残っていないかを確かめます。

console
$ kind get clusters

multi-node が表示されたら、作り直さずにそのまま使えるので、クラスタを作る次のコマンドは飛ばします。表示されなければ、クラスタを作ってから、もう一度一覧します。前の回の kind が表示されても、この回では使いません。手元のマシンの資源(メモリなど)に余裕がなければ、kind delete cluster --name kind で消してから進めてください。

console
$ kind create cluster --name multi-node --config kind-multi-node.yaml
$ kind get clusters

kind get clusters に multi-node が表示されれば、クラスタができています。第3回で決めたとおり、ここからのコマンドには --context kind-multi-node を付けて、操作するクラスタをはっきりさせます。

参考:Quick Start | kind

続けて、ノードを一覧します。

console
$ kubectl get nodes --context kind-multi-node

ノードが 3 つ表示され、STATUS 列が Ready になっていれば準備ができています。Ready になっていなければ、少し待ってからもう一度実行します。NAME 列のノードの名前は、あとで Pod が置かれたノードと見比べるので控えておきます。第15回で見たとおり、kubectl get nodes -l node-role.kubernetes.io/control-plane --context kind-multi-node を実行すると、コントロールプレーンのノードだけが表示されます。

参考:kubectl get | Kubernetes、Node Status | Kubernetes、Implementation details | Kubernetes

ノードごとの Pod の IP アドレスの範囲を見る

ノードの名前と、ノードに割り当てられた Pod の範囲(spec.podCIDR)を表の形で表示します。-o custom-columns は 列の名前:フィールド の形で列を指定する出力の形式です(第6回)。

console
$ kubectl get nodes -o 'custom-columns=NAME:.metadata.name,POD_CIDR:.spec.podCIDR' --context kind-multi-node

参考:Command line tool (kubectl) | Kubernetes、Node | Kubernetes API Reference

「Pod の IP アドレスの範囲」で考えたとおりなら、POD_CIDR 列には、ノードごとに違う範囲が入っているはずです。kind の既定の Pod の範囲は 10.244.0.0/16 なので、どの範囲も 10.244. で始まると考えられます。ノードごとの範囲の / の後ろの数が kube-controller-manager の既定の 24 になっていれば、10.244.<数>.0/24 の形で、<数> がノードごとに違う値になると考えられます。3 つの範囲は重ならないはずです。それぞれの範囲を、ノードの名前と一緒に控えておきます。POD_CIDR 列が空を表す表示になっていたら、このクラスタではノードごとの範囲が割り当てられていないことになります。その場合も、この先の手順はそのまま進められます。

参考:Configuration | kind、Implementation details | Kubernetes、kube-controller-manager | Kubernetes

nginx の Pod と通信元の Pod を作る

2 つのワーカーのノードに nginx の Pod を 1 つずつ置くために、第15回の DaemonSet を使います。第15回の「マニフェストに書くフィールド」と同じ、Toleration を書いていないマニフェストです。nginx-daemonset.yaml という名前で、コマンドを実行するディレクトリに保存します。第15回の途中で Toleration を足したファイルが残っている場合は、次の内容で保存し直してください。

yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-daemonset
  labels:
    app: nginx-daemonset
spec:
  selector:
    matchLabels:
      app: nginx-daemonset
  template:
    metadata:
      labels:
        app: nginx-daemonset
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

参考:DaemonSet | Kubernetes、DaemonSet | Kubernetes API Reference

第15回で見たとおり、この DaemonSet の Pod はコントロールプレーンのノードの Taint を許容しないので、2 つのワーカーのノードに 1 つずつ置かれるはずです。

次は nginx に問い合わせる通信元の Pod です。以下は busybox:1.28 のイメージで、何もせずに待ち続けるコンテナを 1 つ動かす Pod のマニフェストです。client.yaml という名前で保存します。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: client
spec:
  containers:
  - name: busybox
    image: busybox:1.28
    command: ['sh', '-c', 'sleep 3600']

参考:Pod | Kubernetes API Reference、Using Source IP | Kubernetes

busybox:1.28 は第9回・第10回と同じイメージです。公式のチュートリアル(Using Source IP)でも、busybox:1.28 の Pod の中から wget でサーバーに問い合わせています。command の sleep 3600 は一般に、3600 秒(1 時間)待つコマンドです。この Pod は待っているあいだに、kubectl exec(第10回)で中からコマンドを動かすために使います。1 時間たってコンテナが終わっても、restartPolicy の既定は Always なので、kubelet がコンテナを再起動します(第9回)。この Pod にも Toleration を書いていないので、client もワーカーのノードのどちらかに置かれるはずです。

参考:Using Source IP | Kubernetes、Pod Lifecycle | Kubernetes、Taints and Tolerations | Kubernetes

ここからは端末を 2 つ使います。第11回・第13回〜第17回と同じく、1 つ目の端末で変化を追い続け、2 つ目の端末でマニフェストを渡したり、Pod の中でコマンドを動かしたりします。この回で 1 つ目の端末が追うのは Pod です。2 つ目の端末を開いたら、cd でマニフェストを保存したディレクトリに移動しておきます。

1 つ目の端末で、default の Namespace の Pod を監視します。第3回で見たとおり、--watch を付けると、一覧を表示したあとも変化を追い続けます。-o wide を付けて、Pod の IP アドレス(IP 列)と、Pod が置かれたノードの名前(NODE 列)も表示します(第8回)。この監視は片付けの前まで止めずに続けます。

console
$ kubectl get pods --watch -o wide --context kind-multi-node

参考:kubectl get | Kubernetes

Pod がまだ無いので、何も表示されないか、見つからないことを知らせる 1 行が出たあと、止まったように見えると考えられます。

2 つ目の端末で、2 つのマニフェストを渡します。

console
$ kubectl apply -f nginx-daemonset.yaml --context kind-multi-node
$ kubectl apply -f client.yaml --context kind-multi-node

daemonset.apps/nginx-daemonset と pod/client が作られたことを知らせる行が出るはずです。1 つ目の端末には nginx-daemonset- で始まる名前の Pod 2 つと、client の Pod の行が書き足されていくはずです。行は Pending、ContainerCreating、Running と移っていくと考えられます。status.podIP は割り当てられるまで空なので、最初の行の IP 列には、まだ値が無いことを表す表示が出て、あとの行で IP アドレスが入ると考えられます。クラスタを作ったばかりなら、イメージの取得に時間がかかるので、ContainerCreating のまましばらく止まって見えることがあります(第9回)。

参考:Pod Lifecycle | Kubernetes、Pod | Kubernetes API Reference

Pod の IP アドレスとノードを確かめる

1 つ目の端末で 3 つの Pod が Running になったら、2 つ目の端末で、Pod の IP アドレスとノードを一覧します。

console
$ kubectl get pods -o wide --context kind-multi-node

公式のチュートリアルの例(Deployment で作った 2 つの nginx の Pod を、-o wide で一覧した例)では、出力は次のとおりです。

NAME                        READY     STATUS    RESTARTS   AGE       IP            NODE
my-nginx-3800858182-jr4a2   1/1       Running   0          13s       10.244.3.4    kubernetes-minion-905m
my-nginx-3800858182-kna2y   1/1       Running   0          13s       10.244.2.5    kubernetes-minion-ljyd

参考:Connecting Applications with Services | Kubernetes

例では、2 つの Pod が別々のノードに置かれ、それぞれ別の IP アドレスを持っています。NODE 列の kubernetes-minion-905m などは公式の例のクラスタのノードの名前のままです。手元の表示は例と次の点が違うはずです。

  • 行は 3 つで、nginx-daemonset- で始まる 2 つの Pod と、client が並ぶ
  • IP 列と NODE 列の値は手元のクラスタのものになる(例の値とは違う)
  • 例よりも列が多いことがあると考えられる(第8回)。IP 列と NODE 列を探して読む

参考:Connecting Applications with Services | Kubernetes、kubectl get | Kubernetes

NODE 列を、控えておいたノードの名前と見比べます。2 つの nginx の Pod は、2 つのワーカーのノードに 1 つずつ置かれているはずです。client は、どちらかのワーカーのノードにあるはずです。そこで、2 つの nginx の Pod を次の 2 つに分け、それぞれの名前と IP アドレスを控えます。

nginx の Pod見分け方
同じノードの nginx の PodNODE 列が client と同じ
別のノードの nginx の PodNODE 列が client と違う

3 つの Pod の IP 列の値は、すべて違うはずです。クラスタの各 Pod はクラスタ全体で一意な IP アドレスを持つからです。ノードごとの範囲を見る手順で POD_CIDR 列に値が入っていた場合は、各 Pod の IP アドレスがその Pod のノードの範囲に入っているかも見比べてみてください。入っていれば、このクラスタのネットワークプラグイン(kindnetd)は、ノードの範囲から Pod の IP アドレスを選んでいると読めます。入っていなければ、ノードの範囲を使わずに IP アドレスを選んでいると読めます。kindnetd がノードの範囲から選んでいるかどうかは公式ドキュメントで確かめられなかった点なので、手元の表示で確かめるところです。ネットワークモデルは Pod の IP アドレスをノードごとの範囲から選ぶかどうかまでは決めていません。

参考:Services, Load Balancing, and Networking | Kubernetes、Cluster Networking | Kubernetes

ノードをまたいで IP アドレスで通信する

2 つ目の端末で、client の Pod の中で wget を動かし、別のノードの nginx の Pod に IP アドレスで問い合わせます。<別のノードの nginx の Pod の IP アドレス> には、控えた IP アドレスを入れます。kubectl exec の -- の後ろがコンテナの中で動かすコマンドです(第10回)。-q と -O- は第10回と同じで、一般に、進み具合を表示せず、受け取った内容をそのまま画面に出す指定です。http://<IP アドレス>:80/ は一般的な URL の書き方です。Web の通信の決まり(HTTP)で、その IP アドレスの 80 番のポートに、いちばん上のページ(/)を求めるという意味です。:80 は nginx のコンテナが待ち受けるポート(containerPort)です。

console
$ kubectl exec client --context kind-multi-node -- wget -q -O- http://<別のノードの nginx の Pod の IP アドレス>:80/

参考:kubectl exec | Kubernetes、Using Source IP | Kubernetes

<h1>Welcome to nginx!</h1> の行を含む、nginx の初期のページの HTML が表示されれば成功です。公式のチュートリアルにも nginx の Pod の IP アドレスに問い合わせて、この行を含むページが返った例があります(問い合わせ方は手元と違います)。その表示の一部は次のとおりです。

...
<h1>Welcome to nginx!</h1>

参考:Connecting Applications with Services | Kubernetes

数秒たっても何も表示されずに止まったままなら、Ctrl+C で止めます。そのうえで、IP アドレスの打ち間違いが無いかと、相手の Pod の STATUS 列が Running かを見直します。

続けて、同じノードの nginx の Pod にも問い合わせます。

console
$ kubectl exec client --context kind-multi-node -- wget -q -O- http://<同じノードの nginx の Pod の IP アドレス>:80/

こちらも同じように、nginx の初期のページの HTML が表示されるはずです。どちらの問い合わせでも、Service は作っていませんし、ノードのポートに対応付ける設定も書いていません。client は、相手の Pod の IP アドレスとコンテナのポートだけで、別のノードの Pod にも同じノードの Pod にも届いています。ネットワークモデルが求める「すべての Pod が、同じノードでも違うノードでも、ほかのすべての Pod と通信できる」ことの一端を、手元で確かめたことになります。kind のクラスタでこの通信を用意しているのは、ネットワークプラグインの kindnetd だと考えられます。

参考:Services, Load Balancing, and Networking | Kubernetes、Connecting Applications with Services | Kubernetes、Configuration | kind

なお、この回の手順では、送り元の IP アドレスが途中で書き換えられていないこと(NAT が無いこと)までは確かめません。

localhost では別の Pod に届かないことを確かめる

2 つ目の端末で、client の Pod の中から localhost:80 に問い合わせます。第10回のサイドカーと同じ問い合わせ方です。

console
$ kubectl exec client --context kind-multi-node -- wget -q -O- http://localhost:80/

今度は nginx のページは表示されず、つながらないことを知らせるエラーの行が出ると考えられます。エラーの行が出れば想定どおりです。localhost は client の Pod 自身を指し、client の Pod の中には 80 番のポートで待ち受けるコンテナがいないからです。第10回でサイドカーが localhost で nginx に届いたのは、2 つのコンテナが同じ Pod の中にいて、ネットワークの namespace を共有していたからです。別の Pod の nginx には、さきほどのように、その Pod の IP アドレスで届けます。

参考:Pods | Kubernetes、Services, Load Balancing, and Networking | Kubernetes

Pod を作り直して IP アドレスを見比べる

2 つ目の端末で、別のノードの nginx の Pod を消します。<別のノードの nginx の Pod の名前> には控えた名前を入れます。

console
$ kubectl delete pod <別のノードの nginx の Pod の名前> --context kind-multi-node

参考:kubectl delete | Kubernetes

1 つ目の端末には、消した Pod の行が Terminating になり、新しい名前の Pod の行が現れるはずです。第15回で見たとおり、DaemonSet は消された Pod を作り直し、新しい Pod は消した Pod と同じノードに置かれるはずです。新しい Pod が Running になったら、2 つ目の端末で、もう一度一覧します。

console
$ kubectl get pods -o wide --context kind-multi-node

参考:DaemonSet | Kubernetes、DaemonSet | Kubernetes

新しい Pod の IP 列を、消した Pod の IP アドレスと見比べてみてください。公式のチュートリアルは、作り直された Pod は別の IP アドレスになる、と説明しています(Deployment の Pod の例)。手元で同じ IP アドレスになったとしても、それを前提にはできないと考えられます。チュートリアルも IP アドレスが変わることへの対処を Service に任せています。IP アドレスが変わっていれば、新しい Pod に届けるには、新しい IP アドレスで wget を動かし直す必要があります。消した Pod が Terminating で表示されていたら、少し待ってからもう一度実行します。相手が作り直されるたびに IP アドレスを調べ直すのは大変です。この手間をなくすのが、第21回で扱う Service です。

参考:Connecting Applications with Services | Kubernetes、Service | Kubernetes

片付け

1 つ目の端末で Ctrl+C を押して、監視を止めます。

2 つ目の端末で、作った Pod と DaemonSet を、マニフェストを指定して削除します。公式ドキュメントによると、DaemonSet を消すと、DaemonSet が作った Pod も消されます。

console
$ kubectl delete -f client.yaml --context kind-multi-node
$ kubectl delete -f nginx-daemonset.yaml --context kind-multi-node

参考:kubectl delete | Kubernetes、DaemonSet | Kubernetes

kubectl delete は既定では、Pod が消えるまで待ってから終わります。Pod には終了までの猶予の時間(既定では 30 秒)があるので、client を消すコマンドは終わるまで少しかかることがあります。

参考:kubectl delete | Kubernetes、Pod Lifecycle | Kubernetes

少し待ってから、残っていないかを確かめます。

console
$ kubectl get daemonsets,pods --context kind-multi-node

Pod が Terminating で表示されていたら、少し待ってからもう一度実行します。第15回と同じく、見つからないことを知らせる 1 行が出れば、削除できています。

最後に、クラスタを削除し、消えたことを確かめます。

console
$ kind delete cluster --name multi-node
$ kind get clusters

kind delete cluster は、存在しないクラスタを指定してもエラーを返しません。kind get clusters に multi-node が表示されなくなったことを確かめます。kubeconfig に kind-multi-node のコンテキストが残っていたら、第3回の片付けと同じく kubectl config delete-context kind-multi-node で消します。

参考:Quick Start | kind、kubectl config | Kubernetes

注意点

Pod どうしの通信でつまずきやすい点と、クラスタを作るときに決める設定、バージョンで変わる点を、次の表にまとめます。

項目内容
Pod の IP アドレスは変わることがある作り直された Pod は別の IP アドレスになることがある。決まった相手に届けるには Service(第21回)や DNS の名前(第23回)を使う
localhost で届くのは同じ Pod の中だけ別の Pod のコンテナは IP アドレスが別。IP のネットワークで、その Pod の IP アドレスに届ける
区切らない限り、すべての Pod どうしが通信できるネットワークモデルは、意図してネットワークを区切らない限り、すべての Pod どうしの通信を求める。Pod どうしの通信を制御する API として NetworkPolicy がある(第25回)。ネットワークプラグインが対応していないと効果がない
ネットワークプラグインは別に入れるkubeadm では、クラスタを作ったあとに CNI を使う Pod のネットワークのアドオンを入れる。入れるまで CoreDNS は起動せず、1 つのクラスタに入れられる Pod のネットワークは 1 つ
IP アドレスの範囲は重ねないPod、Service、ノードには重ならない IP アドレスを割り当てる。kubeadm の公式ドキュメントは、Pod のネットワークをホストのネットワークと重ねないよう注意を促している(重なると問題が起きやすい)
Pod のネットワークの要件はクラスタの中の通信要件は、Pod どうしと、ノードの上のエージェントから同じノードの Pod への通信。クラスタの外のクライアントに届けるには、Gateway API や Ingress(第24回)、Service の type: LoadBalancer(Service の種類の 1 つ。第22回)を使う
デュアルスタックは v1.23 から安定版IPv4 と IPv6 を両方使うには、デュアルスタックに対応したネットワークプラグインが要る。kind の既定は IPv4 だけ

参考:Services, Load Balancing, and Networking | Kubernetes、Cluster Networking | Kubernetes、Creating a cluster with kubeadm | Kubernetes、Connecting Applications with Services | Kubernetes、Pods | Kubernetes、IPv4/IPv6 dual-stack | Kubernetes、Configuration | kind

spec.hostNetwork: true の Pod は、自分のネットワークの namespace ではなくノード(ホスト)のネットワークの namespace を使います。第4回で見た kube-apiserver などの static Pod がその例です。このような Pod はノードのネットワークの namespace を使うので、ポートの番号もノードと共有します。API リファレンスは、hostNetwork を使うときは、スケジューラーがわかるように ports を指定するべき(should)だとしています。この回の Pod のように hostNetwork を書かなければ、既定の false になり、Pod は自分のネットワークの namespace を持ちます。公式ドキュメントのネットワークモデルは、Windows では、ホストのネットワークを使う Pod(host-network pods)に Pod どうしの通信の決まりは当てはまらない、と注記しています。

参考:Pod | Kubernetes API Reference、Implementation details | Kubernetes、Services, Load Balancing, and Networking | Kubernetes

関連記事

Pod の集まりに変わらない入り口を与える Service と、Service の転送先を表す EndpointSlice については、以下の記事で解説しています。

基本仕様 ・ 第21回 Service を動かして理解するPod の集まりに変わらない入り口を与える Service の仕組みを図で説明します。ラベルセレクタで Pod を選ぶこと、cluster IP、転送先の一覧を持つ EndpointSlice、ノードで通信を Pod へ届ける kube-proxy を押さえ、kind のクラスタで Pod を増減させたときに転送先が自動で変わる様子を確かめる手順を紹介します。

Service の名前で相手を見つけられる、クラスタの中の DNS については、以下の記事で解説しています。

基本仕様 ・ 第23回 なぜ Service 名で通信できるのかService の名前を IP アドレスに変えるクラスタ DNS の仕組みを図で説明します。CoreDNS と kube-dns の Service、kubelet が Pod に書き込む /etc/resolv.conf の search と ndots、Namespace をまたぐ名前の書き方を押さえ、kind のクラスタで名前を引いて確かめる手順を紹介します。

この回で「すべての Pod どうしが通信できる」とした通信を制限する NetworkPolicy と、ネットワークプラグインとの関係については、以下の記事で解説しています。

基本仕様 ・ 第25回 NetworkPolicy を動かして理解するPod の通信を IP アドレスやポートの単位で制限する NetworkPolicy の仕組みを図で説明します。ポリシーに選ばれた Pod だけが隔離されること、許可の規則の書き方、通信を実際に止めるのはネットワークプラグインであることを押さえ、kind のクラスタでポリシーの前後に届き方が変わる様子を確かめる手順を紹介します。

Kubernetes 基本仕様の目次へ