ReplicaSet を動かして理解する
v1.37 時点(2026年10月23日 確認)
目次
この記事では同じ Pod を指定した数だけ動かし続けるリソースである ReplicaSet の仕組みを、図で説明します。ReplicaSet がどの Pod を自分の Pod として数えるのかを、ラベルとラベルセレクタの決まりから説明します。ラベルを書き換えた Pod がどう扱われるのか、数を減らすときにどの Pod が消されるのかもわかります。後半では kind のクラスタで ReplicaSet を作り、Pod のラベルを書き換えて、その Pod が ReplicaSet の管理から外れる様子を観察する手順を示します。
Deployment の Pod を消すと作り直される仕組み(調整ループ)を扱った第6回の内容を前提にしています。直接作った Pod は消すと戻らないことを確かめた第8回の内容も使います。まだの方は先にこちらをどうぞ。
消した Pod が戻ってくる仕組み(調整ループ)コントローラーが実際の状態を望ましい状態に近づけ続ける調整ループの仕組みを図で説明します。Deployment・ReplicaSet・Pod の関係と、Pod を消したときに誰が気づいて代わりを作るのかを押さえ、kind のクラスタで Deployment の Pod を手で削除し、作り直される様子を観察する手順を紹介します。以下の図は、ReplicaSet が持つ 3 つの設定と、ReplicaSet と Pod の 2 種類の結び付きを表しています。
ReplicaSet は spec.selector(ラベルセレクタ)に合う Pod を数え、spec.replicas の数と比べます。足りなければ spec.template(Pod のひな形)から Pod を作り、多すぎれば Pod を消します。作った Pod には、持ち主として ReplicaSet を指す ownerReferences が入ります。実線の「選ぶ」と破線の「持つ」は、第6回の図と同じ意味です。ひな形の箱から出る破線は持ち主の関係ではなく、ひな形から Pod を作る流れを表しています。
参考:ReplicaSet | Kubernetes、Owners and Dependents | Kubernetes
ReplicaSet とは
ReplicaSet は 同じ Pod の複製(replica)を、決まった数だけ常に動かしておくためのリソース です。公式ドキュメントは ReplicaSet の目的を、ある時点で動いている複製の Pod の集まりを安定して保つことだと説明しています。そのため、同じ Pod を指定した数だけ確実に動かしておくためによく使われます。
参考:ReplicaSet | Kubernetes、ReplicaSet | Kubernetes API Reference
公式ドキュメントによると、ReplicaSet は次の 3 つのフィールドで決まります。
| フィールド | 決めること |
|---|---|
spec.selector | 自分のものにできる Pod を見分ける条件(ラベルセレクタ) |
spec.replicas | 保つ Pod の数 |
spec.template | 数を満たすために新しく作る Pod の中身(Pod のひな形) |
第6回で見たとおり、ReplicaSet はふつう自分で作りません。Deployment を作ると、Deployment が ReplicaSet を作って管理します。公式ドキュメントも、独自の更新の手順が要る場合や、更新がまったく要らない場合を除いて、ReplicaSet を直接使わずに Deployment を使うよう勧めています。Deployment は ReplicaSet を管理し、Pod を宣言的に更新する仕組みなど、多くの便利な機能を持つ、より上の段階の仕組みだからです。それでもこの回で ReplicaSet を直接作るのは、Deployment が手を出さない状態で、ReplicaSet そのものの動きを確かめるためです。Deployment は第12回で扱います。
ReplicaSet より前からある ReplicationController というリソースもあります。公式ドキュメントによると、ReplicaSet は ReplicationController の後継で、目的も動きもほとんど同じです。違うのは、ReplicationController が後で説明する集合ベースのセレクタに対応していないことです。そのため、ReplicationController より ReplicaSet が勧められています。
参考:ReplicaSet | Kubernetes、Labels and Selectors | Kubernetes
なぜ ReplicaSet が必要なのか
第8回で見たとおり、直接作った Pod は消えると誰も作り直しません。公式ドキュメントによると、ReplicaSet は、利用者が直接作った Pod の場合とは違い、どんな理由で消えたり終了したりした Pod も置き換えます。理由の例として、ノードの故障や、カーネルの更新のような、Pod を止めるノードの保守が挙がっています。そのため公式ドキュメントは、アプリケーションに Pod が 1 つしか要らない場合でも ReplicaSet を使うよう勧めています。
ReplicaSet は自分の Pod を、名前の一覧ではなくラベルセレクタで決めます。第6回で見たとおり、ReplicaSet が作り直した Pod は、名前も UID も前の Pod と違う、別の Pod です。公式ドキュメントの ReplicaSet の例でも、Pod の名前は frontend-gbgfx のように、作るたびに違う文字列が付きます。もし名前の一覧で覚えていたら、作り直すたびに一覧を書き換える必要がありそうです。ラベルセレクタなら、「tier: frontend のラベルを持つ Pod」という条件は変わらないので、Pod が入れ替わっても同じ条件で数えられると考えられます。公式ドキュメントも、ラベルを使うと、どの Pod がどのまとまりに入るかという対応を、kubectl などのクライアント(API を使う側のプログラム)が覚えておかなくても、利用者が自分の考えるまとまりをオブジェクトと緩く結び付けられる、と説明しています。
参考:Labels and Selectors | Kubernetes、ReplicaSet | Kubernetes、Pod Lifecycle | Kubernetes
ReplicaSet と同じ役目の古いリソース ReplicationController のページには、この考え方がよりはっきり書かれています。ReplicationController はセレクタに合うラベルを持つ Pod をすべて管理し、自分で作った Pod かどうかを区別しません。そのため、動いている Pod に影響を与えずに、ReplicationController を置き換えられるとされています。
ラベルで選ぶので、Pod のラベルを書き換えれば、その Pod を ReplicaSet の数から外せます。公式ドキュメントはこの方法を、調べものやデータの回収のために、Pod を稼働中の Pod の集まりから外す(remove Pods from service)ときに使える、と説明しています。レプリカの数を同時に変えていなければ、外した Pod の代わりは自動で作られるので、ReplicaSet の Pod の数は保たれます。この回の後半で試すのは、この動きです。
ここでの「service」は Pod への通信の入り口になる Service というリソース(第21回)そのものを指すわけではないと考えられます。ただ、公式ドキュメントによると、Service も通信を送る先の Pod をラベルセレクタで決めます。そのため、ReplicaSet と同じラベルで Pod を選ぶ Service があれば、ラベルを書き換えた Pod はその Service の送り先からも外れると考えられます。この回では Service を作らないので、通信への影響は確かめません。
ReplicaSet の仕組み
マニフェストに書く 3 つのフィールド
以下は Pod を 3 つ保つ ReplicaSet のマニフェストです。公式ドキュメントの例(controllers/frontend.yaml)をもとに、コンテナの名前とイメージだけを、これまでの回と同じ nginx に変えています。公式ドキュメントの例では、コンテナの名前は php-redis、イメージは us-docker.pkg.dev/google-samples/containers/gke/gb-frontend:v5 です。このイメージは公式ドキュメントのチュートリアルで使うゲストブック(訪問者がメッセージを書き残す例のアプリケーション)の、PHP で作られたフロントエンドです。後半の「手元で試す」でも、このマニフェストを使います。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: nginx
image: nginx:1.14.2参考:ReplicaSet | Kubernetes、Example: Deploying PHP Guestbook application with Redis | Kubernetes
マニフェストの app: guestbook と tier: frontend は公式ドキュメントの例で使われているラベルです。公式ドキュメントのラベルの使い方の説明では、アプリケーションごとに app の値を変え、ゲストブックのように層(tier)に分かれたアプリケーションでは tier のラベルで層を見分ける例が挙がっています。そこでは、利用者に見える画面を受け持つ側が tier: frontend、ゲストブックの書き込みを保存する Redis の側が tier: backend です。ラベルは、後で説明するとおり Kubernetes の中心の仕組みにとって直接の意味を持たないので、キーも値も、決まりに合っていれば利用者が自由に決めてかまいません。app や tier という名前に特別な働きがあるわけではありません。同じ説明は、app のラベルを使うのは手で問い合わせるときに便利だからで、ツールや自動化には、推奨のラベルの決まりに沿った app.kubernetes.io/name のほうが向いている、としています。推奨のラベルは第42回で扱います。
参考:Labels and Selectors | Kubernetes、Example: Deploying PHP Guestbook application with Redis | Kubernetes
ReplicaSet の apiVersion は第1回と第6回の Deployment と同じ apps/v1 です。公式ドキュメントによると、ReplicaSet にもほかのオブジェクトと同じく apiVersion、kind、metadata が要り、kind は常に ReplicaSet です。spec の各フィールドを、v1.37 時点の公式ドキュメントと API リファレンスに沿って次の表にまとめます。
| フィールド | 内容 |
|---|---|
metadata.name | ReplicaSet の名前。ReplicaSet が作る Pod の名前のもとの一部になる。DNS のサブドメイン名の決まり(第5回)を満たす必要があり、そのうえで公式ドキュメントは、より厳しい DNS ラベルの決まり(第8回)に従うのがよいとしている |
spec.replicas | 望ましい Pod の数。書かなければ 1 になる |
spec.selector | Pod を選ぶラベルセレクタ。必須。Pod のひな形のラベルに合っていなければ、API が受け付けない |
spec.template | Pod のひな形。足りない Pod を作るときに使う。ラベル(spec.template.metadata.labels)が必ず要る |
spec.template.spec.restartPolicy | 書けるのは既定値の Always だけ(第9回) |
参考:ReplicaSet | Kubernetes、ReplicaSet | Kubernetes API Reference
このマニフェストには、ラベルが 2 か所にあります。metadata.labels は ReplicaSet 自身に付けるラベルで、spec.template.metadata.labels は ReplicaSet が作る Pod に付くラベルです。公式ドキュメントによると、ReplicaSet が Pod を見分けるのに使うのは spec.selector です。metadata.labels の app: guestbook と tier: frontend はどちらも Pod を選ぶ条件とは関係ありません。この例では metadata.labels にもセレクタと同じ tier: frontend がありますが、Pod が選ばれるのはセレクタに tier: frontend を書いたからで、metadata.labels に書いたからではありません。なお API リファレンスには、ReplicaSet の metadata.labels が空なら、ReplicaSet が管理する Pod と同じラベルが既定で入る、とも書かれています。
参考:ReplicaSet | Kubernetes、ReplicaSet | Kubernetes API Reference
第6回の Deployment の ReplicaSet と Pod には、pod-template-hash というラベルも付いていました。公式ドキュメントによると、このラベルは Deployment のコントローラーが、Deployment が作るか自分のものにした ReplicaSet に付けるものです。そのため、この回のように ReplicaSet を直接作った場合は付かないと考えられます。
spec.template は Pod のマニフェストの metadata と spec を、そのまま入れ子にした形です。公式ドキュメントによると、ワークロードのリソースのコントローラーは、この Pod のひな形(Pod template)から実際の Pod を作ります。ひな形はワークロードのリソースの望ましい状態の一部です。ひな形の metadata には name を書いていません。公式ドキュメントによると、ReplicaSet の名前が Pod の名前のもとの一部になります。第6回で見たとおり、Pod の名前は generateName の仕組みで、frontend- の後ろに一意な文字列を付けたもの(公式ドキュメントの例では frontend-gbgfx)になります。
参考:Pods | Kubernetes、ReplicaSet | Kubernetes、ReplicaSet | Kubernetes API Reference、ObjectMeta | Kubernetes API Reference
ラベルとラベルセレクタ
第6回で触れたとおり、ラベル は Pod などのオブジェクトに付けるキーと値の組です。公式ドキュメントによると、ラベルは、利用者にとって意味のある、オブジェクトを見分けるための性質を表すのに使います。ただし、ラベルは Kubernetes の中心の仕組みにとって、直接の意味を持ちません。ラベルはオブジェクトを作るときに付けられ、あとからいつでも足したり変えたりできます。1 つのオブジェクトの中で、キーは一意にします。
ラベルのキーと値に使える文字は決まっています。公式ドキュメントの決まりを次の表にまとめます。
| 対象 | 決まり |
|---|---|
| キーの名前の部分 | 必須。63 文字以内。英数字で始まって英数字で終わり、間には -、_、.、英数字を使える |
| キーの接頭辞 | 省略できる。付けるときは DNS のサブドメイン名(253 文字以内)にして、/ で名前と区切る(例:example.com/my-app)。kubernetes.io/ と k8s.io/ は Kubernetes の中心のコンポーネントのために予約されている |
| 値 | 63 文字以内で、空でもよい。空でなければ英数字で始まって英数字で終わり、間には -、_、.、英数字を使える |
参考:Labels and Selectors | Kubernetes、kubectl label | Kubernetes
公式ドキュメントによると、名前や UID と違って、ラベルは一意ではありません。たくさんのオブジェクトが同じラベルを持つことが想定されています。ラベルセレクタ はラベルを条件にしてオブジェクトの集まりを選ぶ仕組みで、公式ドキュメントは Kubernetes でまとまりを作る中心の仕組みだと説明しています。v1.37 時点の API がサポートするセレクタは、等価ベース(equality-based)と集合ベース(set-based)の 2 種類です。
等価ベースのセレクタは、キーと値が等しいかどうかで選びます。使える演算子は =、==、!= の 3 種類です。= と == は同じ意味で「等しい」を表し、!= は「等しくない」を表します。集合ベースのセレクタは値の集まりを使って選びます。演算子は in、notin、exists(キーだけを書く形)の 3 種類です。公式ドキュメントの例と、それぞれが選ぶものを次の表にまとめます。
| 種類 | 例 | 選ぶもの |
|---|---|---|
| 等価ベース | environment = production | キーが environment で、値が production のもの |
| 等価ベース | tier != frontend | キーが tier で値が frontend 以外のもの。tier のキーを持たないものも選ぶ |
| 集合ベース | environment in (production, qa) | キーが environment で、値が production か qa のもの |
| 集合ベース | tier notin (frontend, backend) | キーが tier で値が frontend と backend 以外のもの。tier のキーを持たないものも選ぶ |
| 集合ベース | partition | partition のキーのラベルを持つもの(値は見ない) |
| 集合ベース | !partition | partition のキーのラベルを持たないもの(値は見ない) |
!= と notin がそのキーを持たないオブジェクトも選ぶことに注意してください。セレクタはいくつかの条件(requirement)を , で区切って並べられます。公式ドキュメントによると、条件が複数あるときは、すべてを満たすものだけが選ばれます。, は「かつ」(AND)の意味です。「または」(OR)を表す演算子はありません。値について「または」を表したいときは、集合ベースの in を使います。また、選ばれるオブジェクトはすべての条件を満たしていれば、ほかのラベルを持っていてもかまいません。公式ドキュメントはこのことを等価ベースの節で説明していますが、集合ベースの条件も、条件に書いていないキーのラベルは見ないので、同じと考えられます。
以下の図は、tier: frontend のセレクタを持つ ReplicaSet が、ラベルの違う 4 つの Pod のうち、どれを選ぶかを表しています。
セレクタの条件を満たしていれば、track: daily のようなほかのラベルが付いていても選ばれます。値が違う Pod(tier: debug)と、ラベルの無い Pod は選ばれません。
マニフェストでは ReplicaSet のセレクタを matchLabels と matchExpressions で書きます。公式ドキュメントによると、Job、Deployment、ReplicaSet、DaemonSet のような新しいリソースは、集合ベースの条件にも対応しています。一方で Service(Pod への通信の入り口になり、送り先の Pod をラベルで選ぶリソース。第21回)と ReplicationController のセレクタは、キーと値を並べるだけの形で、等価ベースの条件にしか対応していません。以下は公式ドキュメントにある、2 つの書き方を組み合わせたセレクタの例です。
selector:
matchLabels:
component: redis
matchExpressions:
- { key: tier, operator: In, values: [cache] }
- { key: environment, operator: NotIn, values: [dev] }{ key: tier, ... } は { } で囲んで項目を 1 行に並べる、YAML の書き方です。一般に、key:、operator:、values: を 3 行に分けて書いたのと同じ意味になります。この例は、component が redis で、tier が cache で、environment が dev ではない Pod を選びます。NotIn は集合ベースの notin にあたると考えられるので、environment のラベルを持たない Pod も選ぶと考えられます。2 つのフィールドの意味を、v1.37 時点の API リファレンスに沿って次の表にまとめます。
| フィールド | 内容 |
|---|---|
matchLabels | キーと値の組を並べたもの。1 つの組は、operator が In で、values にその値だけを入れた matchExpressions の 1 項目と同じ意味になる |
matchExpressions | 条件の一覧。各項目は key(ラベルのキー)、operator(演算子)、values(値の一覧)で書く。演算子は In、NotIn、Exists、DoesNotExist の 4 つ |
values | In と NotIn では 1 つ以上の値が必要。Exists と DoesNotExist では空にする |
参考:LabelSelector | Kubernetes API Reference、LabelSelectorRequirement | Kubernetes API Reference
マニフェストの matchExpressions の演算子と、文字列で書くセレクタ(kubectl の -l などで使う形)の演算子は、次のように対応すると考えられます。公式ドキュメントに、この対応をはっきり書いた箇所はありません。In と NotIn は名前から、Exists と DoesNotExist は、キーだけを書く形と、キーの前に ! を付ける形にあたると考えられます。
matchExpressions の演算子 | 対応すると考えられる文字列の形 | 選ぶもの |
|---|---|---|
In | tier in (frontend, debug) | 値が一覧のどれかに当たるもの |
NotIn | tier notin (frontend) | 値が一覧のどれにも当たらないもの(文字列の形の notin では、キーの無いものも含む) |
Exists | tier | そのキーのラベルを持つもの |
DoesNotExist | !tier | そのキーのラベルを持たないもの |
参考:Labels and Selectors | Kubernetes、LabelSelectorRequirement | Kubernetes API Reference、Assigning Pods to Nodes | Kubernetes
「選ぶもの」の列のうち、notin がキーの無いものも選ぶことは、Labels and Selectors のページの文字列の形の説明にあります。matchExpressions の NotIn も同じと考えられますが、公式ドキュメントでは確かめられませんでした。Exists と DoesNotExist の意味は、ノードの割り当ての説明(Assigning Pods to Nodes)にある nodeAffinity と podAffinity の演算子の表で、Exists が「そのキーのラベルがオブジェクトにある」、DoesNotExist が「そのキーのラベルがオブジェクトに無い」と説明されています。
matchLabels と matchExpressions の条件はすべてまとめて「かつ」で結ばれます。空のセレクタの扱いは、ReplicaSet のページには書かれていません。この回のように、ひな形のラベルに合わせて条件を 1 つ以上書いておけば、気にする必要はないと考えられます。参考までに、API リファレンスは、空のラベルセレクタはすべてのオブジェクトに合い、値の無い(null の)ラベルセレクタはどのオブジェクトにも合わない、と説明しています。ただし公式ドキュメントは、空のセレクタや指定しないセレクタの意味は使う場面によって変わる、としています。
参考:LabelSelector | Kubernetes API Reference、Labels and Selectors | Kubernetes、ReplicaSet | Kubernetes
ラベルセレクタは kubectl でも使えます。第4回と第6回で使った kubectl get pods -l app=nginx の -l は、ラベルセレクタで絞り込む指定です。公式ドキュメントによると、-l には等価ベースと集合ベースのどちらの条件も書けます。集合ベースの条件は kubectl get pods -l 'environment in (production, qa)' のように、空白や括弧をシェルに解釈させないよう単一引用符(')で囲んで書きます。
参考:Labels and Selectors | Kubernetes、kubectl get | Kubernetes
ReplicaSet が Pod を自分のものにする決まり
第6回で見たとおり、ReplicaSet と Pod の間には、ラベルで選ぶ関係と持ち主の関係(ownerReferences)の 2 種類の結び付きがあります。公式ドキュメントによると、ReplicaSet が手に入れた(acquired)Pod にはすべて、持ち主の ReplicaSet を見分ける情報が ownerReferences に入ります。ReplicaSet はこのつながりを通して、自分が保っている Pod の状態を知り、それに応じて動きます。
ReplicaSet は自分で作った Pod だけを数えるわけではありません。公式ドキュメントによると、ReplicaSet は新しく手に入れる Pod を、セレクタを使って見つけます。ownerReferences が無いか、あってもコントローラー(第6回の controller: true)を指していない Pod が、セレクタに合えば、ReplicaSet はその Pod をすぐに手に入れます。条件を次の表にまとめます。
| Pod の状態 | セレクタに合うとき |
|---|---|
ownerReferences が無い(第8回のように直接作った Pod など) | ReplicaSet がすぐに自分のものにする |
ownerReferences はあるが、コントローラーを指していない | ReplicaSet がすぐに自分のものにする |
ほかのコントローラーが持ち主(controller: true)になっている | ReplicaSet は自分のものにしないと読み取れる(下で説明) |
参考:ReplicaSet | Kubernetes、OwnerReference | Kubernetes API Reference
2 行目の Pod はふつうの使い方ではあまり見ないと考えられます。公式ドキュメントによると、ReplicaSet などの従属物の ownerReferences は Kubernetes が自動で入れ、手で書き換えることもできますが、ふつうはその必要はありません。2 行目は、たとえば利用者が controller を付けずに ownerReferences を手で書いた場合などにあたると考えられます。
3 行目について、公式ドキュメントに直接の記述はありません。ただ、ReplicaSet のページの注には、同じ spec.selector を持ち、Pod のひな形のラベルと中身が違う 2 つの ReplicaSet は、それぞれもう一方の ReplicaSet が作った Pod を無視する、と書かれています。Owners and Dependents のページも、持ち主の関係はラベルとセレクタの仕組みとは別のもので、Kubernetes の各部分が自分の管理していないオブジェクトに手を出さないようにするためにある(avoid interfering with objects they don’t control)と説明しています。この 2 つから、ほかのコントローラーが持ち主になっている Pod を、ReplicaSet はセレクタに合っても自分のものにしないと読み取れます。
参考:ReplicaSet | Kubernetes、Owners and Dependents | Kubernetes
公式ドキュメントには、セレクタに合うラベルを付けた Pod を直接作ったときの例があります。frontend の ReplicaSet が Pod を 3 つ動かしているところに、tier: frontend のラベルを持つ pod1 と pod2 を直接作った例です。2 つの Pod のマニフェスト(公式ドキュメントの pods/pod-rs.yaml)はこの記事には載せていません。公式ドキュメントの例では ReplicaSet のひな形とは別のイメージ(gcr.io/google-samples/hello-app の 2.0 と 1.0)を指定しています。2 つの Pod は ReplicaSet に手に入れられ、そのまま ReplicaSet の望ましい数を超えるので、すぐに終了させられます。このときの kubectl get pods の出力は次のとおりです。
順番を逆にして、pod1 と pod2 を先に作ってから ReplicaSet を作ると、ReplicaSet は 2 つの Pod を手に入れ、足りない 1 つだけを新しく作ります。公式ドキュメントの例の出力は次のとおりです。
公式ドキュメントは、このようにして ReplicaSet は中身のそろっていない Pod の集まりも持てる、と説明しています。例の pod1 と pod2 は ReplicaSet のひな形とは別のイメージで動いています。ReplicaSet は Pod の中身がひな形と同じかどうかを見ず、セレクタに合うかどうかで数えるということです。そのため公式ドキュメントは 直接作る Pod には ReplicaSet のセレクタに合うラベルを付けないよう 強く勧めています。
セレクタの重なりにも注意が要ります。上で見たとおり、ほかの ReplicaSet が持ち主になっている Pod は無視されますが、持ち主のいない Pod は、セレクタが合うどの ReplicaSet にも手に入れられる可能性があります。公式ドキュメントによると、ReplicaSet のような API の種類では、同じ Namespace の中で 2 つのセレクタが重なってはいけません。重なると、コントローラーがそれを食い違う指示とみなし、Pod をいくつ動かすべきか決められなくなることがあります。ReplicaSet のページも Pod のひな形のラベルをほかのコントローラーのセレクタと重ねないよう注意しています。ほかのコントローラーがその Pod を自分のものにしようとするからです。持ち主の関係で互いの Pod を無視する場面があっても、セレクタは重ねないのが原則 です。
参考:Labels and Selectors | Kubernetes、ReplicaSet | Kubernetes
ラベルを書き換えて Pod を外す
公式ドキュメントによると、Pod のラベルを書き換えるとその Pod を ReplicaSet から外せて、レプリカの数を同時に変えていなければ、外した Pod は自動で置き換えられます。以下の図は、3 つの Pod のうち 1 つのラベルを書き換えたあとに起きることを、コマ送りで表しています。図の A〜D は Pod の名前の略です。kube-apiserver、kube-scheduler、kubelet は省き、利用者と replicaset-controller の操作を、Pod や Pod の枠へ直接描いています。
ReplicaSet から見ると、Pod A はセレクタに合わなくなったので、数に入りません。そのため replicaset-controller は、Pod を消したときと同じように、足りない 1 つを作ります。公式ドキュメントにあるのは、ラベルで外せること、外した Pod は自動で置き換えられること、この方法を調べものやデータの回収に使えることまでです。外した Pod を ReplicaSet が消さないとは、はっきりとは書かれていません。ただ、調べものやデータの回収に使えるとしている以上、外した Pod A は消されずに動き続けると考えられます。そうだとすれば、第6回で Pod を消したときとの違いは、Pod A が消えずに残ることです。
外した Pod A の ownerReferences がどうなるかは、このメディアで確かめた範囲の kubernetes.io の公式ドキュメントには書かれていません。Kubernetes の設計の提案(2017 年の文書)には、手がかりになる記述があります。ただしこの文書は「一部だけ実装(partially implemented)」と記されたもので、置かれているリポジトリは保管用として読み取り専用になっています。書かれている内容が今の Kubernetes の作りと同じとは限りません。この文書には、コントローラーは、自分が持つオブジェクトがセレクタに合わなくなったら、ownerReferences から自分を外して手放す、と書かれています。これに従えば、Pod A の ownerReferences からは ReplicaSet が外れ、Pod A は持ち主のいない Pod になると考えられます。後半の「手元で試す」で確かめられます。
ラベルを元に戻すと、Pod A は再びセレクタに合います。持ち主のいない Pod になっていれば、公式ドキュメントの決まりどおり、ReplicaSet がすぐに Pod A を手に入れます。ownerReferences に ReplicaSet が残っていた場合も、Pod A はセレクタに合うので、ReplicaSet の数に入ると考えられます。どちらの場合も、セレクタに合う Pod は 4 つになり、望ましい数の 3 を超えます。公式ドキュメントの pod1 と pod2 の例と同じく、ReplicaSet は多すぎる 1 つの Pod を終了させます。この結論は、ownerReferences がどうなるかの推測には左右されません。どの Pod が終了させられるかは、次の「数を変えたときに消す Pod の選び方」の決まりで決まります。
数を変えたときに消す Pod の選び方
ReplicaSet の Pod の数を変えるには、spec.replicas を書き換えます。公式ドキュメントによると、ReplicaSet のコントローラーは、セレクタに合う Pod が望ましい数だけ使える状態で動いているよう保ちます。kubectl scale を使うと、spec.replicas を書き換えられます。たとえばリファレンスの例の kubectl scale --replicas=3 rs/foo は foo という ReplicaSet の数を 3 にします。
数を減らすとき、ReplicaSet のコントローラーは、セレクタに合う Pod を並べ替えて、消す Pod を選びます。公式ドキュメントはここで並べ替える Pod を「available pods」と書いています。ただし、次の決まりの 1 つ目に Pending の Pod が含まれるので、第6回の「使える(available)Pod」(Ready になってから minReadySeconds 以上たった Pod)とは意味が違い、その ReplicaSet が数えている Pod(Ready かどうかにかかわらない)を指すと考えられます。公式ドキュメントが挙げる一般的な決まりは、次の 4 つです。番号は公式ドキュメントの並びのとおりです。
Pendingの Pod(ノードが決まらない Pod を含む)を先に消すcontroller.kubernetes.io/pod-deletion-costのアノテーションが付いていれば、値が小さい Pod を先に消す- 同じ ReplicaSet の Pod が多く動いているノードの Pod を、少ないノードの Pod より先に消す
- 作られた時刻が違えば、新しく作られた Pod を先に消す(作られた時刻は、対数の目盛りで整数の区切りにまとめて比べる)
公式ドキュメントによると、4 つのすべてが同じなら、消す Pod は無作為に選ばれます。
4 つ目の決まりは、平たく言えば「新しい Pod を先に消すが、作られた時刻が近い Pod どうしでは差がつかないことがある」ということです。細かい計算は気にしなくてかまいません。公式ドキュメントは「対数の目盛り」の計算を説明していませんが、作られた時刻が近い Pod どうしは同じ区切りにまとめられると考えられます。その場合は、ほかの決まりでも差がつかなければ、無作為に選ばれます。
2 つ目の決まりにあるアノテーションは、ラベルと同じキーと値の組ですが、オブジェクトを見分けたり選んだりするのには使いません。アノテーションは第42回で扱います。公式ドキュメントによると、controller.kubernetes.io/pod-deletion-cost は Pod に付けて、同じ ReplicaSet のほかの Pod と比べたときの、その Pod を消すコストを表します。値の範囲は -2147483648 から 2147483647 で、付けていない Pod は 0 とみなされます。v1.37 時点では、このアノテーションの機能は v1.22 からベータで、既定で有効です。ただし、この順番は努力目標(best-effort)で、消す順番の保証はありません。
ReplicaSet だけではできないこと
ReplicaSet は Pod の数を保ちますが、Pod の中身を入れ替えることはしないと考えられます。公式ドキュメントの Pods のページによると、Pod のひな形を変えたり、新しいひな形に切り替えたりしても、すでにある Pod には直接の影響はありません。たとえば、ReplicaSet のひな形のイメージを新しいバージョンに変えても、動いている Pod は古いイメージのままだと考えられます。
公式ドキュメントは決まった手順で Pod を新しい中身に更新するには Deployment を使うよう勧めています。ReplicaSet はローリングアップデート(Pod を少しずつ入れ替える更新)に直接対応していないからです。Deployment は ReplicaSet を持ち、ReplicaSet と Pod を宣言的に、サーバー側(server-side)のローリングアップデートで更新します。サーバー側とは、kubectl が手元で 1 つずつ入れ替えるのではなく、クラスタの中のコントローラーが入れ替えを進めるという意味だと考えられます。公式ドキュメントによると、ReplicaSet は単独でも使えますが、今は主に、Deployment が Pod の作成・削除・更新を進めるための仕組みとして使われています。
手元で試す
ここまでの内容を手元の kind のクラスタで試す手順を示します。ReplicaSet を作って Pod のラベルと持ち主を確かめたあと、Pod を 1 つ選んでラベルを書き換え、その Pod が ReplicaSet の管理から外れる様子を観察します。最後にラベルを元に戻し、ReplicaSet が多すぎる Pod を終了させる様子も見ます。コマンドは macOS や Linux のシェル(bash や zsh)で実行する前提で書いています。Windows では WSL(Windows の中で Linux を動かす仕組み)などを使ってください。試す環境は次のとおりです。
| 項目 | 内容 |
|---|---|
| kind | v0.33.0 |
| Kubernetes | v1.37.0(kind v0.33.0 の既定のノードイメージ) |
| ノード構成 | シングルノード(クラスタ名 kind):コントロールプレーン 1 |
| 必要なもの | Docker、kubectl(v1.36〜v1.38) |
参考:Release v0.33.0 · kubernetes-sigs/kind、Version Skew Policy | Kubernetes
kind でクラスタを作る手順は、以下の記事で解説しています。この回ではシングルノードのクラスタを使います。ラベルで Pod を選ぶ仕組みは、ノードの数に関係しないからです。
kind で検証用のクラスタを作るDocker のコンテナをノードにして、手元のマシンに Kubernetes のクラスタを作るツール kind の仕組みを図で説明します。kind create cluster で何が起きるかを押さえ、シングルノードとマルチノードのクラスタを作って、ノードの正体が Docker のコンテナであることを確かめる手順を紹介します。シングルノードのクラスタを用意する
まず、前の回のクラスタが残っていないかを確かめます。
$ kind get clusters
kind が表示されたら、作り直さずにそのまま使えるので、クラスタを作る次のコマンドは飛ばします。表示されなければ、クラスタを作ってから、もう一度一覧します。
$ kind create cluster
$ kind get clusters
kind get clusters に kind が表示されれば、クラスタができています。第3回で決めたとおり、ここからのコマンドには --context kind-kind を付けて、操作するクラスタをはっきりさせます。
続けて、ノードを一覧します。
$ kubectl get nodes --context kind-kind
ノードが 1 つ表示され、STATUS 列が Ready になっていれば準備ができています。Ready になっていなければ、少し待ってからもう一度実行します。
ReplicaSet を作る
「マニフェストに書く 3 つのフィールド」のマニフェストを、frontend.yaml という名前で、コマンドを実行するディレクトリに保存します。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: nginx
image: nginx:1.14.2前の回のクラスタを使い続けている場合は、先に tier のラベルを持つ Pod が無いことを確かめます。-l tier は、値にかかわらず tier のキーのラベルを持つものを選ぶ、集合ベースの条件です。
$ kubectl get pods -l tier --context kind-kind
Pod が見つからないことを知らせる 1 行が出れば、そのまま進めます。Pod が表示されたら、その Pod を kubectl delete pod <Pod の名前> --context kind-kind で消してから進みます。第6回の nginx-deployment が残っていても、ラベルが app: nginx なので、この回の手順には影響しません。
参考:Labels and Selectors | Kubernetes、kubectl get | Kubernetes
ReplicaSet を作り、できたことを確かめます。rs は replicasets の短い名前です(第6回)。
$ kubectl apply -f frontend.yaml --context kind-kind
$ kubectl get rs --context kind-kind
参考:ReplicaSet | Kubernetes、Command line tool (kubectl) | Kubernetes
公式ドキュメントの例では、kubectl get rs の出力は次のとおりです。
第6回で見たとおり、Deployment のページの説明では、DESIRED 列は望ましい数、CURRENT 列は今動いている数、READY 列は利用者が使える数です。frontend の行の READY 列が 3 になるまで、少し待ってから何度か実行します。クラスタを作り直したばかりなら、nginx:1.14.2 のイメージの取得に時間がかかることがあります(第9回)。
ReplicaSet と Pod のラベルを確かめる
Pod を、tier のラベルの値を列に加えて一覧します。-L(--label-columns)は、指定したラベルの値を列にして表示する指定です。
$ kubectl get pods -L tier --context kind-kind
公式ドキュメントにある別の例を引用します。app=nginx の 3 つの Pod に tier=fe のラベルを付けたあと、kubectl get pods -l app=nginx -L tier で一覧した例です。Pod の名前とラベルの値は手元と違いますが、いつもの列の最後に TIER 列が加わる形は同じです。
手元では、frontend- で始まる名前の Pod が 3 つ並び、TIER 列はどれも frontend になるはずです。名前の末尾の文字列は、手元では例と違う値になります。第6回の nginx-deployment の Pod が残っていれば、その Pod も並びます。公式ドキュメントの例(kubectl get pods -Lapp -Ltier -Lrole で一覧した例)では、そのラベルを持たない Pod の列は <none> と表示されています。tier のラベルが無い Pod の TIER 列も、同じように表示されると考えられます。
参考:ReplicaSet | Kubernetes、Labels and Selectors | Kubernetes
続けて、ReplicaSet を詳しく表示します。
$ kubectl describe rs frontend --context kind-kind
公式ドキュメントの例では、表示は次のとおりです。
見るところを次の表にまとめます。
| 見るところ | 表していると考えられるもの |
|---|---|
Selector: | ReplicaSet のセレクタ(spec.selector)。例では tier=frontend |
Labels: | ReplicaSet 自身のラベル(metadata.labels)。Pod を選ぶ条件ではない |
Replicas: | 今ある数と望ましい数 |
Pod Template: の Labels: | Pod のひな形のラベル |
Events: | 例では、replicaset-controller が Pod を 3 つ作ったことが記録されている |
Pod Template: の Labels: は必ず Selector: の条件を満たしています。ひな形のラベルがセレクタに合っていなければ、API が ReplicaSet を受け付けないからです。
手元の表示は、Pod Template: の Containers: の下が nginx: になり、Image: が nginx:1.14.2 になる点が例と違うはずです。マニフェストのコンテナの名前とイメージを変えたからです。Selector: が tier=frontend で、Pod Template: の Labels: も tier=frontend であることを確かめてください。
ラベルを書き換えて Pod を管理から外す
ここでは端末(ターミナル)を 2 つ使います。1 つ目の端末で Pod の変化を追い続け、2 つ目の端末で Pod のラベルを書き換えます。
1 つ目の端末で、tier のラベルの値を列に加えて、Pod を監視します。第3回で見たとおり、--watch を付けると、一覧を表示したあとも変化を追い続けます。
$ kubectl get pods -L tier --watch --context kind-kind
3 つの Pod の行が表示されたあとは、変化が起きるまで止まったように見えるはずです。-l tier=frontend で絞り込まずに監視するのは、ラベルを書き換えた Pod も画面に残して、行方を追うためです。
2 つ目の端末で、3 つの Pod のうち 1 つのラベルを書き換えます。kubectl label はリソースのラベルを書き換えるコマンドです。<Pod の名前> には 1 つ目の端末に表示された名前を 1 つ入れ、この名前を控えておきます。すでにあるキーの値を変えるので、--overwrite を付けます。
$ kubectl label pod <Pod の名前> tier=debug --overwrite --context kind-kind
リファレンスによると、--overwrite を付けないと、すでにあるラベルを書き換えようとしたときにエラーになります。成功すると、pod/<Pod の名前> labeled のような 1 行が表示されるはずです。公式ドキュメントの kubectl label の例でも、pod/my-nginx-2035384211-j5fhi labeled のような行が表示されています。
参考:kubectl label | Kubernetes、Labels and Selectors | Kubernetes
1 つ目の端末を見ると、行が書き足されていくはずです。--watch の表示はすでに表示した行を消さずに、変化を受け取るたびに行を書き足していくものです(第8回)。見るところを次の表にまとめます。
| 見るところ | 起きていること |
|---|---|
ラベルを書き換えた Pod の行が、TIER 列が debug で書き足される | Pod のラベルが変わり、ReplicaSet のセレクタに合わなくなった |
新しい名前(frontend- で始まる)の Pod の行が加わる | replicaset-controller が、足りない 1 つをひな形から作った |
新しい Pod の行が何度か表示され、STATUS 列が Running になる | kube-scheduler がノードを選び、kubelet がコンテナを起動した |
行の順番や、新しい Pod の STATUS 列が Running になるまでに表示される値は、タイミングで変わります。ラベルを書き換えた Pod の行の STATUS 列は、Running のまま変わらないはずです。「ラベルを書き換えて Pod を外す」で見たとおり、外した Pod は消されずに動き続けると考えられるからです。Terminating の行が現れないはずであることも、第6回で Pod を消したときとの違いです。新しい Pod の STATUS 列が Running になったら、1 つ目の端末で Ctrl+C を押して監視を止めます。
続けて、もう一度 Pod を一覧し、セレクタに合う Pod だけの一覧と比べます。
$ kubectl get pods -L tier --context kind-kind
$ kubectl get pods -l tier=frontend --context kind-kind
1 つ目のコマンドでは、TIER 列が frontend の Pod が 3 つと、debug の Pod が 1 つ、合わせて 4 つ並ぶはずです。2 つ目のコマンドでは、tier=frontend のセレクタに合う 3 つだけが並び、ラベルを書き換えた Pod は表示されないはずです。ReplicaSet が数えているのは、2 つ目のコマンドで見えている 3 つにあたります。
参考:Labels and Selectors | Kubernetes、ReplicaSet | Kubernetes
集合ベースの条件も試します。in を使うと、値が frontend か debug のどちらかの Pod を選べます。
$ kubectl get pods -l 'tier in (frontend, debug)' --context kind-kind
4 つの Pod が並ぶはずです。等価ベースの , は「かつ」なので、-l tier=frontend,tier=debug のように並べても、値が frontend か debug の Pod を選ぶことにはなりません。tier の値が frontend であり、同時に debug でもある Pod は無いので、試すとどの Pod も選ばれないと考えられます。値の「または」を表すには、このように in を使います。
最後に、ReplicaSet の数を確かめます。
$ kubectl get rs frontend --context kind-kind
DESIRED、CURRENT、READY の列はどれも 3 のはずです。Pod は全部で 4 つ動いていますが、ReplicaSet が数えるのはセレクタに合う 3 つだけです。kubectl describe rs frontend --context kind-kind を実行すると、Events: の欄に、新しい Pod の名前の SuccessfulCreate の行が加わっていると考えられます。
外した Pod の持ち主を確かめる
Pod の名前、tier のラベルの値、持ち主の種類と名前を、表の形で取り出します。-o custom-columns は 列の名前:フィールド の形で列を指定する出力の形式です(第6回)。.metadata.labels.tier は、ラベルのうち tier のキーの値を指します。
$ kubectl get pods -o 'custom-columns=NAME:.metadata.name,TIER:.metadata.labels.tier,OWNER_KIND:.metadata.ownerReferences[0].kind,OWNER:.metadata.ownerReferences[0].name' --context kind-kind
参考:Command line tool (kubectl) | Kubernetes、kubectl get | Kubernetes
TIER 列が frontend の 3 つの Pod は、OWNER_KIND 列が ReplicaSet、OWNER 列が frontend になるはずです。TIER 列が debug の Pod は、「ラベルを書き換えて Pod を外す」で説明した設計の提案のとおりなら、OWNER_KIND 列と OWNER 列が値の無いことを表す表示(<none> など)になると考えられます。値の無いフィールドがどう表示されるかは、公式ドキュメントでは確かめられませんでした。ここは推測なので、手元の表示が違っていても、この回の手順には影響しません。
参考:Controller Ref(design-proposals-archive、2026年10月時点の内容)、Owners and Dependents | Kubernetes
ラベルを元に戻す
外した Pod のラベルを tier=frontend に戻し、ReplicaSet がどう動くかを観察します。1 つ目の端末で、もう一度 Pod の監視を始めます。
$ kubectl get pods -L tier --watch --context kind-kind
2 つ目の端末で、外した Pod のラベルを元に戻します。<外した Pod の名前> には、さきほど控えた名前を入れます。
$ kubectl label pod <外した Pod の名前> tier=frontend --overwrite --context kind-kind
1 つ目の端末では、戻した Pod の行が TIER 列が frontend で書き足されたあと、4 つの Pod のうち 1 つの行の STATUS 列が Terminating になります。セレクタに合う Pod が 4 つになり、ReplicaSet が望ましい数の 3 を超えた分を終了させるからです。公式ドキュメントの pod1 と pod2 の例と同じ動きです。
どの Pod が終了させられるかは、「数を変えたときに消す Pod の選び方」の決まりで決まります。この手順では、どの Pod も動いていて、アノテーションも付けておらず、ノードも 1 つです。そのため 1〜3 つ目の決まりでは差がつかず、4 つ目の決まり(新しく作られた Pod を先に消す)がかかわると考えられます。ただし、作られた時刻は対数の目盛りでまとめて比べられるので、どれが選ばれるかは確実には言えません。ラベルを戻した Pod が終了させられることも、さきほど作られた Pod が終了させられることもあり得ると考えられます。Terminating の行の Pod が消えるまで少し待ち、Ctrl+C を押して監視を止めます。
もう一度、Pod とその持ち主を一覧します。
$ kubectl get pods -o 'custom-columns=NAME:.metadata.name,TIER:.metadata.labels.tier,OWNER_KIND:.metadata.ownerReferences[0].kind,OWNER:.metadata.ownerReferences[0].name' --context kind-kind
TIER 列が frontend の Pod は 3 つに戻り、どれも OWNER 列が frontend になるはずです。終了させられた Pod がまだ一覧に残っていれば、少し待ってからもう一度実行します。ラベルを戻した Pod が残った場合は、その Pod の OWNER 列も frontend になっているはずです。「外した Pod の持ち主を確かめる」の一覧で、その Pod の OWNER 列に値が無かったなら、ReplicaSet が持ち主のいない Pod をもう一度自分のものにしたことになります。そのときの OWNER 列が frontend のままだった場合は、持ち主の参照が外れずに残っていたことになり、この一覧だけではもう一度手に入れたかどうかは決められません。
片付け
作った ReplicaSet を、マニフェストを指定して削除します。
$ kubectl delete -f frontend.yaml --context kind-kind
公式ドキュメントによると、ReplicaSet を kubectl delete で消すと、既定ではガベージコレクター(不要になった従属物を片付けるコントローラー)が、従属物の Pod も自動で消します(第6回)。少し待ってから、ReplicaSet と、tier のラベルを持つ Pod が残っていないかを確かめます。
$ kubectl get rs,pods -l tier --context kind-kind
参考:ReplicaSet | Kubernetes、Garbage Collection | Kubernetes、kubectl delete | Kubernetes
Pod が Terminating で表示されていたら、少し待ってからもう一度実行します。何も見つからないことを知らせる 1 行が出れば、削除できています。frontend の ReplicaSet は -l tier の条件にも合うので(metadata.labels に tier: frontend があるため)、残っていればこの一覧に出ます。「ラベルを元に戻す」を飛ばした場合は、TIER 列が debug だった Pod が残っていると考えられます。持ち主のいない Pod は ReplicaSet を消しても消えないからです。その場合は kubectl delete pod <Pod の名前> --context kind-kind で消します。
参考:Owners and Dependents | Kubernetes、Garbage Collection | Kubernetes
最後に、クラスタを削除し、消えたことを確かめます。
$ kind delete cluster
$ kind get clusters
kind delete cluster は存在しないクラスタを指定してもエラーを返しません。kind get clusters に kind が表示されなくなったことを確かめます。kubeconfig に kind-kind のコンテキストが残っていたら、第3回の片付けと同じく kubectl config delete-context kind-kind で消します。
注意点
ReplicaSet とラベルセレクタでつまずきやすい点と、バージョンで変わる点を、次の表にまとめます。
| 項目 | 内容 |
|---|---|
| ReplicaSet はふつう直接作らない | 公式ドキュメントは、ReplicaSet を使いたいときは Deployment を使うよう勧めている。Deployment が持つ ReplicaSet は直接いじらない |
| セレクタはひな形のラベルに合わせる | spec.selector が spec.template.metadata.labels に合っていなければ、API が受け付けない |
| 数えるのはセレクタに合う Pod | ReplicaSet はひな形と中身が同じかどうかを見ない。ラベルが合えば、別のイメージで動く Pod も数に入る |
| 直接作る Pod にセレクタと同じラベルを付けない | 持ち主のいない Pod は、セレクタに合えば ReplicaSet にすぐ手に入れられる。数を超えていれば、そのまま終了させられる |
| セレクタをほかと重ねない | 同じ Namespace で ReplicaSet のセレクタが重なると、コントローラーが Pod の数を決められなくなることがある |
!= と notin はキーの無いものも選ぶ | tier!=frontend は、tier のラベルが無いオブジェクトも選ぶ。「または」の演算子は無いので、値の「または」は in で書く |
| ラベルを書き換えた Pod は残ると考えられる | セレクタから外れた Pod の代わりが作られる。外した Pod は消されずに動き続けると考えられるので、Pod の合計は 1 つ増える。要らなくなったら自分で消す |
| セレクタは作ったあとで変えられない | apps/v1 の ReplicaSet の spec.selector は必須で、作ったあとは変えられない |
| ひな形を変えても今の Pod は変わらない | ReplicaSet はローリングアップデートに直接対応していない。中身を入れ替えるときは Deployment を使う |
| 消す Pod の順番は保証されない | 数を減らすときの選び方は一般的な決まりで、差がつかなければ無作為。pod-deletion-cost(v1.37 時点でベータ、既定で有効)も努力目標 |
参考:ReplicaSet | Kubernetes、Deployments | Kubernetes、Labels and Selectors | Kubernetes、Pods | Kubernetes、Deprecated API Migration Guide | Kubernetes
セレクタは作ったあとで変えられないので、最初に決めておきます。公式ドキュメントの Deprecated API Migration Guide によると、ReplicaSet の apps/v1(v1.9 から使える。古い API バージョンの提供は v1.16 で終わった)では、spec.selector は必須で、作ったあとは変えられません。Deployment のページも、Deployment のセレクタは作ったあとで変えられないとし、セレクタは前もって計画しておくよう勧めています。
参考:Deprecated API Migration Guide | Kubernetes、Deployments | Kubernetes
関連記事
ReplicaSet を持ち、Pod の中身をローリングアップデートで入れ替える Deployment と、切り戻しの仕組みについては、以下の記事で解説しています。
Deployment とローリングアップデートの仕組みReplicaSet を持ち、Pod を宣言的に更新する Deployment の仕組みを図で説明します。ひな形を変えたときに新しい ReplicaSet へ Pod を少しずつ移すローリングアップデート、pod-template-hash の役割、リビジョンと切り戻しを押さえ、kind のクラスタでイメージを更新して rollout undo で戻す手順を紹介します。ラベルとアノテーションの違いと、ラベルの付け方の設計については、以下の記事で解説しています。
ラベルセレクタで通信の宛先の Pod を選ぶ Service については、以下の記事で解説しています。