Pod を動かして理解する

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

Kubernetes 基本仕様第8回 / 全45回 ・ 第2部 ワークロード
目次

この記事では Kubernetes で作って管理できる最小の単位である Pod の仕組みを、図で説明します。Pod とコンテナはどう違うのか、Pod の中のコンテナは何を共有するのか、Pod を直接作って消すと何が起きるのかがわかります。後半では kind のクラスタで Pod を直接作って削除し、もう戻らないことを確かめる手順を示します。

Deployment の Pod を消すと作り直される仕組み(調整ループ)を扱った第6回の内容を前提にしています。まだの方は先にこちらをどうぞ。

基本仕様 ・ 第6回 消した Pod が戻ってくる仕組み(調整ループ)コントローラーが実際の状態を望ましい状態に近づけ続ける調整ループの仕組みを図で説明します。Deployment・ReplicaSet・Pod の関係と、Pod を消したときに誰が気づいて代わりを作るのかを押さえ、kind のクラスタで Deployment の Pod を手で削除し、作り直される様子を観察する手順を紹介します。

以下の図はノードの上で動く Pod と、その中のコンテナの関係を表しています。

ノードの上の Pod と、Pod の中で動くコンテナ

Kubernetes がノードに置いたり、管理したりする単位はコンテナではなく Pod です。コンテナは Pod の中で動きます。図の左の Pod のように、Pod にコンテナを 1 つだけ入れるのがいちばん多い使い方です。IP アドレスはコンテナごとではなく Pod ごとに付きます。ノードの kubelet は自分のノードに割り当てられた Pod を受け持ち、Pod の spec に書かれたコンテナを動かします(第4回、第5回)。図の破線の「受け持つ」は、kubelet が Pod を担当する関係です。第6回の図の破線とは違い、持ち主の関係(ownerReferences)を表すものではありません。

参考:Pods | Kubernetes、Pod | Kubernetes API Reference、Containers | Kubernetes

Pod とは

Pod の説明に入る前に、第1回から使ってきた「コンテナ」を確かめておきます。公式ドキュメントはコンテナを「アプリケーションを、実行に必要なもの(依存するもの)と一緒にまとめる技術」と説明しています。必要なものごとまとめてあるので、どこで動かしても同じように動きます。動いているコンテナの中身は、ノードの OS の上で動くプロセス(動いているプログラム)で、ほかのコンテナやマシンそのものから隔てられています。コンテナの元になるのがコンテナイメージです。イメージはアプリケーションのコード、その実行に必要な環境、ライブラリ、欠かせない設定の既定値など、アプリケーションを動かすのに必要なもの一式を入れた、すぐに動かせるパッケージです。第1回から使っている nginx:1.14.2 もイメージの名前です。

参考:Containers | Kubernetes、Pod Lifecycle | Kubernetes、What is Docker? | Docker Docs、What is a container? | Docker Docs

Pod は 1 つ以上のコンテナと、それらが共有するストレージとネットワーク、コンテナの動かし方の仕様をまとめたもの です。公式ドキュメントは Pod を、Kubernetes で作って管理できる、最も小さなデプロイの単位(smallest deployable units)としています。名前の pod はクジラの群れ(a pod of whales)や、えんどう豆のさや(pea pod)というときの pod と同じ意味です。

参考:Pods | Kubernetes

公式ドキュメントによると、Pod の中身は常に同じ場所に置かれ、一緒にスケジュールされ(どのノードで動かすかが一緒に決まり)、共有の環境の中で動きます。公式ドキュメントは Pod を、アプリケーションのための「論理的なホスト」にたとえています。ホストはプログラムを動かすマシンのことです。Pod は比較的密に結び付いたコンテナを入れておく 1 台のマシンのようなものと考えるとつかみやすいでしょう。

参考:Pods | Kubernetes

Pod の使い方は、公式ドキュメントでは次の 2 つに分けられています。

使い方内容
コンテナが 1 つの Podいちばん多い使い方。Pod は 1 つのコンテナを包むものと考えてよい。Kubernetes はコンテナを直接ではなく Pod を管理する
協調する複数のコンテナの Pod密に結び付き、資源を共有する必要がある複数のコンテナを 1 つの Pod にまとめる。比較的高度な使い方で、密に結び付いている場合だけに使う

参考:Pods | Kubernetes

同じアプリケーションをいくつも動かして全体の処理能力を増やしたいときは、コンテナではなく Pod を増やします。公式ドキュメントによると、1 つの Pod は、あるアプリケーションの 1 つのインスタンス(動いている 1 つの実体)を動かすためのものです。Pod を増やすことを複製(replication)と呼び、複製した Pod はふつう Deployment などのワークロードのリソースと、そのコントローラーがまとめて作って管理します(第6回)。複数のコンテナを入れた Pod(起動時に先に動く init コンテナを含む)は第10回で扱います。

参考:Pods | Kubernetes

なぜ Pod が必要なのか

Kubernetes はコンテナを 1 つずつ直接扱わず、Pod という単位にまとめて扱います。公式ドキュメントによると、Pod は協調して 1 つのまとまったサービスをつくる複数のプロセス(コンテナ)を支えるように設計されています。Pod の中のコンテナはクラスタの同じ物理マシンか仮想マシンに自動で一緒に置かれます。そのうえで、資源や依存するものを共有し、互いにやり取りし、いつどう終了するかを調整できます。もしコンテナを単位にすると、必ず一緒に動かしたいコンテナどうしが別々のノードに置かれないようにする仕組みが、別に要ると考えられます。

参考:Pods | Kubernetes

Pod を単位にしているので、Kubernetes がコンテナを動かすときに決めることも、Pod ごとにまとまります。主なものを次の表にまとめます。

決めることPod との関係
どのノードで動かすかkube-scheduler は、ノードが決まっていない Pod を見つけて、その Pod を動かすノードを選ぶ。Pod の中のコンテナは同じノードで動く
どの IP アドレスで届くかIP アドレスは Pod ごとに付く(IPv4 や IPv6 といったアドレスの種類ごとに 1 つ。IPv4 と IPv6 は 10.88.0.3 と 2001:db8::1 のような、IP アドレスの形式の違い)。Pod の中のコンテナはそれを共有する
いくつ動かすか1 つの Pod がアプリケーションの 1 つのインスタンス。数を増やすときは Pod を増やす
コンテナをどう動かすかPod の spec に書く。割り当てられたノードの kubelet が、それを読んでコンテナを動かす

参考:Kubernetes Scheduler | Kubernetes、Pods | Kubernetes、Pod | Kubernetes API Reference

一方で、Pod そのものには消えたときに自分を作り直す仕組みがありません。公式ドキュメントによると、Pod の中のコンテナが失敗したときは、Kubernetes がそのコンテナを再起動することがあります。しかし、クラスタが回復できない形で Pod が失敗したとき(たとえば、Pod が割り当てられたノードが故障したとき)は、Kubernetes はそれ以上 Pod を直そうとせず、Pod を消して、自動の回復をほかのコンポーネントに任せます。公式ドキュメントは比較的使い捨ての Pod を管理する仕事を、コントローラーという一段上の仕組みが受け持つと説明しています。第6回で見た replicaset-controller がその例です。

参考:Pod Lifecycle | Kubernetes

公式ドキュメントの Pods のページは、1 つしか動かさない Pod でも、ふつうは Pod を直接作る必要はなく、Deployment や Job などのワークロードのリソースで作るとしています。ReplicaSet のページは、アプリケーションに Pod が 1 つしか要らない場合でも、Pod を直接作らず ReplicaSet を使う よう勧めています。第6回で見たとおり、ReplicaSet は Deployment を作れば Deployment が作ってくれます。この回であえて Pod を直接作るのは、コントローラーが手を出さない状態で、Pod そのものの性質を確かめるためです。

参考:Pods | Kubernetes、ReplicaSet | Kubernetes

Pods のページには、ほかのワークロードのリソースとして Job と StatefulSet も挙がっています。Job は終わりまで動いて止まる一度きりの処理のためのリソースです。StatefulSet はデータを保存し続ける場所や、変わらないネットワーク上の名前が要るアプリケーションの Pod を管理するためのリソースです。Job は第16回、StatefulSet は第14回で扱います。

参考:Pods | Kubernetes、Jobs | Kubernetes、StatefulSets | Kubernetes

Pod の仕組み

マニフェストに書く Pod の中身

以下は nginx のコンテナを 1 つ動かす Pod のマニフェストです。第5回で使ったものと同じ、公式ドキュメントの例をそのまま引用しています。後半の「手元で試す」でも、このマニフェストを使います。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

参考:Pods | Kubernetes

apiVersion・kind・metadata・spec の役割は第5回で扱いました。ここでは Pod に固有のフィールドを、v1.37 時点の API リファレンスに沿って次の表にまとめます。

フィールド内容
metadata.namePod の名前。DNS のサブドメイン名の決まり(第5回)で付ける。Pod の名前はコンテナから見たホスト名にもなる(「Pod の中のコンテナが共有するもの」で説明)ため、公式ドキュメントは、より厳しい DNS ラベルの決まり(63 文字以内で、小文字の英数字と - だけを使うなど)に従うのがよいとしている
spec.containersPod に属するコンテナの一覧。少なくとも 1 つ必要。作ったあとでコンテナを足したり減らしたりはできない
spec.containers[*].nameコンテナの名前。DNS ラベルの決まりで付け、Pod の中で一意にする。作ったあとは変えられない
spec.containers[*].imageコンテナイメージの名前
spec.containers[*].ports[*].containerPortコンテナが待ち受けるポートの番号。API リファレンスの説明では、Pod の IP アドレスで公開する(ほかから届くようにする)ポート

参考:Pod | Kubernetes API Reference、Pods | Kubernetes、Object Names and IDs | Kubernetes

containers は項目を並べたもの(list)で、containers[*].name の [*] は「各項目の」という意味です。公式ドキュメントでも spec.containers[*].image のようにこの書き方が使われています。一般に、ポートは 1 つの IP アドレスの中で、通信の相手のプログラムを見分ける番号です。プログラムが決まったポートに届く通信を受け付けられるように待っていることを、ポートで待ち受けると言います。この回のマニフェストでは nginx のコンテナのポートとして 80 番を書いています。

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

ports はコンテナが待ち受けるポートを書いておくフィールドです。ただし API リファレンスは ここに書かなくても、そのポートに届かなくなるわけではない と注意しています。コンテナの中で 0.0.0.0(すべてのアドレス)で待ち受けているポートには、ports に書いていなくてもネットワークから届きます。一方で、ports の項目には名前(name)を付けられ、付けた名前は Service(Pod への通信の入り口になるリソース。第21回)の targetPort から参照できます。

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

Pod の中のコンテナが共有するもの

公式ドキュメントによると、Pod の共有の環境はコンテナどうしを隔てるのに使われるのと同じ、Linux の namespace や cgroup などの仕組みでできています。namespace は Kubernetes の Namespace(第3回)とは別の Linux の仕組みで、Docker の公式ドキュメントはコンテナという隔てられた作業場所を namespace で作ると説明しています。cgroup はプロセスに割り当てる資源を制限する仕組みです。この回では名前だけ知っておけば十分です。

参考:Pods | Kubernetes、What is Docker? | Docker Docs、About cgroup v2 | Kubernetes

公式ドキュメントによると、Pod が中のコンテナに用意する共有の資源は、ネットワークとストレージの 2 つです。それぞれを次の表にまとめます。

共有するもの内容
ネットワークPod には、アドレスの種類ごとに一意の IP アドレスが付く。Pod の中のコンテナは、IP アドレスとポートを含むネットワークの namespace を共有し、localhost(自分自身、つまり同じマシンを指す名前)で互いに通信できる
ストレージPod は共有のボリューム(Pod の中のコンテナから使えるディレクトリ)を指定できる。Pod の中のすべてのコンテナがボリュームを使えるので、データを共有できる。コンテナの 1 つが再起動しても、ボリュームのデータは残る

参考:Pods | Kubernetes

以下の図は 2 つのコンテナを入れた Pod の中で、コンテナがネットワークとボリュームを共有する様子を表しています。

同じ Pod の中のコンテナが共有する、ネットワーク(IP アドレスとポート)とボリューム

localhost で届くのは、同じ Pod の中のコンテナどうしだけです。同じ Pod の中のコンテナは共有メモリのような、OS の標準のプロセス間通信(IPC)でもやり取りできます。一方、別の Pod のコンテナは IP アドレスが別で、特別な設定をしなければ、IPC ではやり取りできません。別の Pod のコンテナとは IP のネットワークで通信します。

参考:Pods | Kubernetes

公式ドキュメントによると、同じ Pod の中のコンテナは IP アドレスとポートの空間を共有するので、Pod の外とやり取りするときは、ポートなどの使い方をコンテナどうしで調整する必要があります。IP アドレスとポートを共有しているので、たとえば同じ Pod の中の 2 つのコンテナが、同じポート番号で同時に待ち受けることはできないと考えられます。また、Pod の中のコンテナからは、システムのホスト名が Pod の name と同じに見えます。Pod どうしの通信は第20回、ボリュームは第26回で扱います。

参考:Pods | Kubernetes

1 つのノードに留まる Pod

公式ドキュメントによると、Pod がスケジュールされるのは、その一生で一度だけです。Pod を特定のノードに割り当てることを binding、使うノードを選ぶ過程を scheduling と呼びます。Pod が作られると(利用者が直接作っても、コントローラーが作っても)、kube-scheduler がノードを選び、Pod の spec.nodeName にそのノードの名前が入ります(第5回)。API リファレンスによると、spec.nodeName に値が入ると、そのノードの kubelet が Pod のライフサイクルを受け持ちます。

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

Pod は次のどれかが起きるまで、割り当てられたノードに留まります。

  • Pod の処理が終わる(一度動いて終わるプログラムの Pod。第16回の Job など)
  • Pod のオブジェクトが削除される
  • 資源が足りないために、Pod が退避(eviction)させられる
  • ノードが故障する

参考:Pods | Kubernetes

退避はノードの資源が足りなくなったときなどに、Pod を終了させることです。たとえば kubelet はノードの資源を取り戻すために、自分から Pod を終了させることがあります(node-pressure eviction)。

参考:Node-pressure Eviction | Kubernetes

公式ドキュメントによると、ある Pod(UID で見分けられる Pod)が別のノードに「スケジュールし直される」ことはありません。代わりに、ほとんど同じ新しい Pod に置き換えられることがあります。置き換えの Pod は前の Pod と同じ名前(metadata.name)にすることもできますが、metadata.uid は前の Pod と違います。UID はクラスタの全期間を通じて、作られたオブジェクトごとに違う値だからです(第5回)。置き換えの Pod が前と同じノードに置かれる保証もありません。

参考:Pod Lifecycle | Kubernetes、Object Names and IDs | Kubernetes

ここで、コンテナの再起動と Pod の再起動を混同しないよう注意します。公式ドキュメントは、Pod はプロセスではなくコンテナを動かすための環境 であり、削除されるまで存在し続けると説明しています。第1回で見たように、コンテナのプロセスが止まると、kubelet は Pod の restartPolicy に従って、同じ Pod の中でコンテナを動かし直します。このとき Pod は同じ Pod のままです。コンテナの状態と再起動の仕組みは第9回で扱います。

参考:Pods | Kubernetes、Pod Lifecycle | Kubernetes

Pod の中身も作ったあとはほとんど変えません。公式ドキュメントは、コンテナは状態を持たず、変更しないもの(stateless and immutable)として使うことが想定されていると説明しています。動いているコンテナのコードは変えず、変えたいときは、変更を入れた新しいイメージを作り、そのイメージからコンテナを作り直すのが正しい手順です。Pod の更新にも制限があります。v1.37 時点の公式ドキュメントによると、作ったあとの Pod の spec で変えられるのは、コンテナのイメージ(image)など一部のフィールドだけです(変えられるフィールドの一覧は、この節の最後の補足にまとめます)。

参考:Containers | Kubernetes、Pods | Kubernetes

ワークロードのリソースでは、Pod のひな形を変えると、コントローラーは今ある Pod を書き換えず、新しいひな形から新しい Pod を作ります。公式ドキュメントは、Pod が比較的短命で、使い捨てのもの(relatively ephemeral, disposable entities)として設計されていると説明しています。Pod は書き換えて使い続けるものではなく作り直して入れ替えるものだということです。

参考:Pods | Kubernetes

直接作った Pod を消したときに起きること

Pod を kubectl delete で消したときの流れは、第6回で扱いました。直接作った Pod でも流れは同じです。要点を次の表にまとめます。

順番担当すること
1利用者(kubectl)kubectl delete pod で、Pod の削除を kube-apiserver に頼む
2kube-apiserverPod に、削除する時刻と猶予の時間(既定は 30 秒)を書き込む。Pod は終了中になる
3Pod のノードの kubeletPod が終了中になったことに気づき、コンテナのプロセスに TERM シグナル(終了を求める合図)を送る。猶予の時間が過ぎても動いていれば強制的に止める
4Pod のノードの kubeletPod を API からすぐに消すよう求める
5kube-apiserverPod のオブジェクトを消す。以降は、どのクライアントからも見えない

参考:Pod Lifecycle | Kubernetes

違うのは、このあとです。第6回の Deployment の Pod では、replicaset-controller が終了中の Pod を数に入れず、足りない分の Pod を作りました。直接作った Pod にはそのような担当がいません。公式ドキュメントの ReplicaSet のページは、利用者が直接作った Pod の場合とは違い、ReplicaSet はどんな理由で消えたり終了したりした Pod も置き換える、と説明しています。裏を返せば、直接作った Pod は消えても誰も置き換えないということです。

参考:ReplicaSet | Kubernetes、Pod Lifecycle | Kubernetes

以下の図は直接作った Pod と、ReplicaSet が持つ Pod とで、Pod を作り直す担当がいるかどうかを比べたものです。

直接作った Pod と ReplicaSet が持つ Pod の違い(作り直す担当がいるかどうか)

この回の図では線の種類を次の意味で使っています。実線はリクエストや通信の線です。この図の実線「直接作る」は、利用者が kubectl で Pod の作成を頼む操作を表します(前の図の実線は通信や読み書き)。第6回の図の実線(ラベルで選ぶ関係)とは別の意味です。破線は管理する関係です。この図では ReplicaSet が Pod を持つ持ち主の関係(第6回と同じ)を、冒頭の図では kubelet が Pod を受け持つ関係を表します。直接作った Pod には持ち主がいないので、消えたあとに差を埋めようとするコントローラーもいません。

持ち主の関係は従属物の metadata.ownerReferences に記録されます。第6回で見たとおり、持ち主は種類・名前・UID で指すオブジェクト(ReplicaSet など)です。Pod を作った利用者が持ち主として記録されるわけではありません。公式ドキュメントによると、ReplicaSet、DaemonSet、Deployment、Job、CronJob などの従属物には、Kubernetes がこのフィールドを自動で入れます。手で入れることもできますが、ふつうはその必要はありません。ReplicaSet のページも、持ち主の参照(OwnerReference)が無い Pod があることを前提に、そうした Pod の扱いを説明しています。利用者が直接作った Pod の ownerReferences は、手で入れない限り空です。後半の「手元で試す」で確かめます。ただし第6回で見たとおり、直接作った Pod でも、ラベルが ReplicaSet のセレクタに合えば、その ReplicaSet のものになることがあります。この回のマニフェストにはラベルが無いので、その心配はありません。

参考:Owners and Dependents | Kubernetes、OwnerReference | Kubernetes API Reference、ReplicaSet | Kubernetes

起きたことごとに、直接作った Pod と ReplicaSet(Deployment)が持つ Pod でどう違うかを、次の表にまとめます。

起きたこと直接作った PodReplicaSet が持つ Pod
コンテナのプロセスが止まるkubelet が restartPolicy に従って、同じ Pod の中でコンテナを再起動する同じ
Pod を削除する戻らないreplicaset-controller が代わりの Pod を作る
ノードが故障するKubernetes がやがて Pod を消す。代わりは作られない代わりの Pod が作られ、kube-scheduler が正常なノードに置く
資源が足りずに退避させられるPod は退避を生き残らない。代わりは作られない代わりの Pod が作られる

参考:Pod Lifecycle | Kubernetes、ReplicaSet | Kubernetes、Pods | Kubernetes、Node-pressure Eviction | Kubernetes

コンテナの再起動は kubelet の仕事なので、直接作った Pod でも起きます。ワークロードのリソースが加えるのは、Pod そのものがなくなったときに代わりを作る仕組みです。公式ドキュメントは ReplicaSet を、1 台のマシンのプロセスではなく複数のノードにまたがる複数の Pod を見張る、プロセスの監視役のようなものだとたとえています。ReplicaSet はノードの中でのコンテナの再起動を、各ノードで動いて Pod を受け持つプログラム(kubelet など)に任せています。

参考:ReplicaSet | Kubernetes、Pod Lifecycle | Kubernetes

手元で試す

ここまでの内容を手元の kind のクラスタで試す手順を示します。Pod を直接作り、ノードや IP アドレス、持ち主を確かめたあと、Pod を削除して戻らないことを確かめます。最後に同じマニフェストでもう一度作り、名前が同じでも別の Pod になることを確かめます。コマンドは macOS や Linux のシェル(bash や zsh)で実行する前提で書いています。Windows では WSL(Windows の中で Linux を動かす仕組み)などを使ってください。試す環境は次のとおりです。

項目内容
kindv0.33.0
Kubernetesv1.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 でクラスタを作る手順は、以下の記事で解説しています。この回ではシングルノードのクラスタを使います。ノードの数に関係しない仕組みを試すからです。

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

シングルノードのクラスタを用意する

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

console
$ kind get clusters

kind が表示されたら、作り直さずにそのまま使えるので、クラスタを作る次のコマンドは飛ばします。表示されなければ、クラスタを作ってから、もう一度一覧します。

console
$ kind create cluster
$ kind get clusters

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

参考:Quick Start | kind

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

console
$ kubectl get nodes --context kind-kind

ノードが 1 つ表示され、STATUS 列が Ready になっていれば準備ができています。Ready になっていなければ、少し待ってからもう一度実行します。

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

Pod を直接作る

「マニフェストに書く Pod の中身」で引用した Pod のマニフェストを、simple-pod.yaml という名前で、コマンドを実行するディレクトリに保存します。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

参考:Pods | Kubernetes

第5回でも同じ名前の nginx という Pod を作りました。前の回のクラスタを使い続けている場合は、先に Pod を一覧して確かめます。

console
$ kubectl get pods --context kind-kind

一覧の NAME 列に nginx があれば、この回の「片付け」の kubectl delete -f simple-pod.yaml --context kind-kind で消してから進みます。第6回や第7回の nginx-deployment- で始まる Pod が残っていても、この回の手順には影響しません。ただ、見分けやすくするため、kubectl delete deployment nginx-deployment --context kind-kind で消しておくとよいでしょう。第6回で見たとおり、Deployment を消すと、その ReplicaSet と Pod も消えます。

参考:kubectl get | Kubernetes、kubectl delete | Kubernetes、Garbage Collection | Kubernetes

Pod を作り、ノードの名前などを加えて一覧します。-o wide はテキストの形式に追加の情報を加えて表示する指定です(第3回)。

console
$ kubectl apply -f simple-pod.yaml --context kind-kind
$ kubectl get pods -o wide --context kind-kind

参考:Command line tool (kubectl) | Kubernetes、kubectl get | Kubernetes

公式ドキュメントの別の例(Deployment で作った 2 つの 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

手元では NAME 列が nginx の行が 1 つ表示されるはずです。STATUS 列が Running になっていなければ、少し待ってからもう一度実行します。IP 列が Pod の IP アドレス、NODE 列が Pod を割り当てたノードの名前です。シングルノードのクラスタなので、NODE 列は kubectl get nodes で表示されたノードの名前になるはずです。kind の Quick Start の例では、クラスタ名 kind のコントロールプレーンのノードのコンテナは kind-control-plane という名前なので、NODE 列も同じような名前になると考えられます。手元の表示は例よりも列が多いことがあると考えられます。IP 列と NODE 列を探して読んでください。1 分ほど待っても Running にならなければ、第5回と同じく次の kubectl describe で原因を探します。

参考:Pod Lifecycle | Kubernetes、Debug Pods | Kubernetes、Quick Start | kind

Pod の中身と持ち主を確かめる

Pod を詳しく表示します。

console
$ kubectl describe pod nginx --context kind-kind

公式ドキュメントの例(Deployment で作った Pod を表示した例)では、表示の先頭と末尾は次のとおりです。

Name:         nginx-deployment-67d4bdd6f5-w6kd7
Namespace:    default
Priority:     0
Node:         kube-worker-1/192.168.0.113
Start Time:   Thu, 17 Feb 2022 16:51:01 -0500
Labels:       app=nginx
              pod-template-hash=67d4bdd6f5
Annotations:  <none>
Status:       Running
IP:           10.88.0.3
IPs:
  IP:           10.88.0.3
  IP:           2001:db8::1
Controlled By:  ReplicaSet/nginx-deployment-67d4bdd6f5
Containers:
  nginx:
(省略)
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  34s   default-scheduler  Successfully assigned default/nginx-deployment-67d4bdd6f5-w6kd7 to kube-worker-1
  Normal  Pulling    31s   kubelet            Pulling image "nginx"
  Normal  Pulled     30s   kubelet            Successfully pulled image "nginx" in 1.146417389s
  Normal  Created    30s   kubelet            Created container nginx
  Normal  Started    30s   kubelet            Started container nginx

参考:Debug Running Pods | Kubernetes

見るところを次の表にまとめます。

見るところ表しているもの
Node:Pod を割り当てたノード(/ の後ろはノードの IP アドレスと考えられる)
IP:、IPs:Pod の IP アドレス。例では IPv4 と IPv6 の 2 つが付いている
Controlled By:この Pod を管理するコントローラー(持ち主)。例では ReplicaSet
Containers:Pod の中のコンテナごとの情報。nginx: はコンテナの名前
Events: の From 列イベントを記録したコンポーネント。例では default-scheduler がノードを割り当て、kubelet がイメージを取得してコンテナを作り、起動している

参考:Debug Running Pods | Kubernetes、Pods | Kubernetes

default-scheduler は既定のスケジューラーの名前です。公式ドキュメントによると、Kubernetes の既定のスケジューラーは kube-scheduler です。例の IP アドレスが 2 つあるのは、IPv4 と IPv6 の両方を使う構成(デュアルスタック)のクラスタだからです。Pod にはアドレスの種類ごとに 1 つずつ IP アドレスが付きます。

参考:Configure Multiple Schedulers | Kubernetes、Kubernetes Scheduler | Kubernetes、Pods | Kubernetes、IPv4/IPv6 dual-stack | Kubernetes

手元の表示は例と次の点が違うはずです。

  • Name: は nginx、Labels: は <none> のような表示になる(マニフェストにラベルを書いていないため。表示の形は推測)
  • Controlled By: の行が無い(直接作った Pod には持ち主がいないため。表示されないことは推測)
  • IP アドレスは IPv4 の 1 つだけ(kind のクラスタの既定は IPv4 だけを使う構成のため)
  • Containers: の下には、コンテナの名前 nginx: が 1 つだけ並ぶ
  • イメージを取得した場合、Events: の Pulling の行は Pulling image "nginx:1.14.2" のようにタグ付きになる(表示の形は推測)

参考:Configuration | kind、Owners and Dependents | Kubernetes、Debug Running Pods | Kubernetes

Events: の欄では、ノードを割り当てたのが kube-scheduler(default-scheduler)、コンテナを起動したのが kubelet であることを確かめてください。Pulling の行が無いこともあります。nginx:1.14.2 のように :latest 以外のタグを付け、imagePullPolicy を書かなかった場合、imagePullPolicy は IfNotPresent になります(第5回)。IfNotPresent では、イメージはノードに無いときだけ取得されます。そのため、前の回で同じイメージを使ったノードではイメージを取得せず、Pulling の行が無いなど、例と違う表示になると考えられます。

参考:Images | Kubernetes

続けて、Pod の UID と ownerReferences を取り出します。-o jsonpath は第5回で使った、フィールドを指定して取り出す出力の形式です。

console
$ kubectl get pod nginx -o jsonpath='{.metadata.uid}{"\n"}{.metadata.ownerReferences}{"\n"}' --context kind-kind

参考:JSONPath Support | Kubernetes

1 行目に Pod の UID が表示されます。2 行目は空になるはずです。直接作った Pod には、手で入れない限り ownerReferences が入らないからです。第5回で見たとおり、kubectl get の --allow-missing-template-keys の既定は true なので、無いフィールドを指定してもエラーにはなりません。第6回で Deployment の Pod の持ち主を確かめたときは、ownerReferences に ReplicaSet を指す項目がありました。

参考:kubectl get | Kubernetes、Owners and Dependents | Kubernetes、ReplicaSet | Kubernetes

あとで比べるために、UID をファイルに書き出しておきます。

console
$ kubectl get pod nginx -o jsonpath='{.metadata.uid}{"\n"}' --context kind-kind > uid-before.txt

Pod を削除して戻らないことを確かめる

ここでは端末(ターミナル)を 2 つ使います。1 つ目の端末で Pod の変化を追い続け、2 つ目の端末で Pod を削除します。2 つ目の端末も simple-pod.yaml と uid-before.txt を置いたディレクトリで開いてください。

1 つ目の端末で Pod を監視します。第3回で見たとおり、-w(--watch)を付けると、一覧を表示したあとも変化を追い続けます。

console
$ kubectl get pods --watch --context kind-kind

参考:kubectl get | Kubernetes

nginx の行が表示されたあとは、変化が起きるまで止まったように見えるはずです。

2 つ目の端末で Pod を削除します。

console
$ kubectl delete pod nginx --context kind-kind

参考:kubectl delete | Kubernetes

kubectl delete は既定(--wait=true)では、Pod が消えるまで待ってから終わります。Pod には終了までの猶予の時間(既定では 30 秒)があるので、終わるまで少しかかることがあります。

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

1 つ目の端末を見ると、nginx の行が何度か表示されるはずです。--watch の表示は変化を受け取るたびに行を書き足していくもので、すでに表示した行は消えません。そのため Pod が API から消えても、nginx の行は画面に残ったままになると考えられます。最後に表示される行も、STATUS 列が Terminating の行のままのことがあると考えられます。Pod が消えたかどうかは、監視を止めたあとの kubectl get pods で確かめます。見るところを次の表にまとめます。

見るところ起きていること
nginx の行の STATUS 列が Terminating になるkube-apiserver が Pod に削除の時刻を書き込み、Pod が終了中になった
新しい名前の Pod の行は加わらない終了中の Pod の代わりを作るコントローラーがいない

参考:Pod Lifecycle | Kubernetes、ReplicaSet | Kubernetes

第6回で Deployment の Pod を消したときは、消した Pod が Terminating のあいだに、新しい名前の Pod の行が加わりました。この回では、新しい行は現れないはずです。

2 つ目の端末の kubectl delete が終わったら、1 分ほど待ちます。代わりの Pod が遅れて現れることがないかを確かめるためです。第6回では、代わりの Pod は消した Pod が Terminating のあいだに現れていました。1 分ほど待っても 1 つ目の端末に新しい行が加わらなければ、その端末で Ctrl+C を押して監視を止めます。ここからあとのコマンドは 2 つ目の端末で続けます(1 つ目の端末は閉じて構いません)。もう一度 Pod を一覧します。

console
$ kubectl get pods --context kind-kind

一覧に nginx は無いはずです。ほかに Pod を作っていなければ、Pod は 1 つも表示されません。その場合は、一覧の代わりに No resources found in default namespace. のような、Pod が見つからないことを知らせる 1 行が表示されると考えられます。エラーではなく default の Namespace に Pod が 1 つも無いという正常な結果です。直接作った Pod は消すと戻りません。Pod のオブジェクトは kube-apiserver から消え、それを作り直すコントローラーもいないからです。

参考:Pod Lifecycle | Kubernetes、ReplicaSet | Kubernetes

同じマニフェストでもう一度作る

同じマニフェストで Pod をもう一度作り、UID を表示します。

console
$ kubectl apply -f simple-pod.yaml --context kind-kind
$ kubectl get pod nginx -o jsonpath='{.metadata.uid}{"\n"}' --context kind-kind
$ cat uid-before.txt

2 行目のコマンドで表示した UID と、cat で表示した削除前の UID を見比べます。名前は同じ nginx でも、UID は違うはずです。UID はクラスタの全期間を通じて、作られたオブジェクトごとに違う値だからです。消した Pod を戻すには、このように利用者が自分で作り直すしかありません。作り直した Pod も、前の Pod が戻ってきたものではなく 同じ名前の別の Pod です。この作り直しを自動で引き受けるのが、ReplicaSet などのワークロードのリソースです。

参考:Object Names and IDs | Kubernetes、Pod Lifecycle | Kubernetes

片付け

作った Pod を、マニフェストを指定して削除し、消えたことを確かめます。

console
$ kubectl delete -f simple-pod.yaml --context kind-kind
$ kubectl get pods --context kind-kind

kubectl get pods の一覧に nginx が無ければ、削除できています。書き出した UID のファイルも消します。

console
$ rm uid-before.txt

参考:kubectl delete | Kubernetes

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

console
$ kind delete cluster
$ kind get clusters

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

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

注意点

Pod を扱うときにつまずきやすい点と、後から変えられない点、バージョンで変わる点を、次の表にまとめます。

項目内容
Pod は直接作らないのが基本1 つしか動かさない Pod でも、Deployment や Job などのワークロードのリソースで作る。状態を持ち続ける Pod なら StatefulSet を検討する
直接作った Pod は、消えたら戻らない削除、ノードの故障、資源不足による退避のどれでも、代わりは作られない
kubectl run で作るのも Podkubectl run は指定したイメージを Pod で動かすコマンド。作られるのは Pod そのものなので、この回で確かめた直接作った Pod と同じく、消えたら戻らない
コンテナの再起動と Pod の再起動は別Pod はプロセスではなくコンテナを動かす環境。コンテナが再起動しても、Pod は削除されるまで同じ Pod
作ったあとの Pod はほとんど変えられないv1.37 時点では、通常の更新で変えられる spec のフィールドは spec.containers[*].image など一部だけ(一覧と例外は「1 つのノードに留まる Pod」の補足)。コンテナを足したり減らしたりもできない。変えたいときは Pod を作り直す
作り直した Pod は別の Pod同じ名前で作っても UID は違う。前と同じノードに置かれるとも限らない
複数のコンテナは密に結び付くときだけ1 つの Pod に複数のコンテナを入れるのは比較的高度な使い方。数を増やしたいときは、コンテナではなく Pod を増やす
static Pod は例外第3回と第4回で見た kube-apiserver などの static Pod は、コントローラーが kube-apiserver を通して管理するのではなくノードの kubelet が直接見張り、失敗すると再起動する

参考:Pods | Kubernetes、Pod Lifecycle | Kubernetes、ReplicaSet | Kubernetes、kubectl run | Kubernetes、Pod | Kubernetes API Reference、Object Names and IDs | Kubernetes、Static Pods | Kubernetes

ワークロードのリソースはこの先の回で 1 つずつ扱います。ReplicaSet は第11回、Deployment は第12回、StatefulSet は第14回、Job は第16回です。

関連記事

Pod のフェーズ(Pending や Running など)、コンテナの状態、restartPolicy による再起動の仕組みについては、以下の記事で解説しています。

基本仕様 ・ 第9回 ・ 準備中 Pod のライフサイクルと再起動の仕組み 公開したら、ここから読めるようになります。

1 つの Pod に複数のコンテナを入れる、init コンテナとサイドカーの仕組みについては、以下の記事で解説しています。

基本仕様 ・ 第10回 ・ 準備中 init コンテナとサイドカーの仕組み 公開したら、ここから読めるようになります。

Pod の数を保つ ReplicaSet と、ReplicaSet が Pod を選ぶラベルセレクタについては、以下の記事で解説しています。

基本仕様 ・ 第11回 ・ 準備中 ReplicaSet を動かして理解する 公開したら、ここから読めるようになります。

Kubernetes 基本仕様の目次へ