マニフェストと宣言的 API の仕組み

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

Kubernetes 基本仕様第5回 / 全45回 ・ 第1部 クラスタの仕組み
目次

この記事では Kubernetes に作ってほしいものとその望ましい状態を書いたファイルである マニフェスト と、マニフェストを受け取る 宣言的 API の仕組みを、図で説明します。マニフェストの apiVersion・kind・metadata・spec・status がそれぞれ何を表すのか、spec と status を誰が書くのかがわかります。後半では kind のクラスタで kubectl explain を使ってフィールドの意味を確かめ、Pod の spec と status を作成直後と数秒後で比べる手順を示します。

コントロールプレーンとノードの構成を扱った第4回の内容を前提にしています。まだの方は先にこちらをどうぞ。

基本仕様 第4回 コントロールプレーンとノードの構成クラスタを形づくるコントロールプレーンとノードの構成を図で説明します。kube-apiserver・etcd・kube-scheduler・kube-controller-manager と、kubelet・コンテナランタイム・kube-proxy の役割を押さえ、kind のクラスタで kube-system の Pod を一覧して各コンポーネントと対応づける手順を紹介します。

以下の図は、1 つの Pod について、spec と status をどのコンポーネントが書き込むかを表しています。

Pod のオブジェクトの spec と status に書き込むコンポーネント

利用者がマニフェストで書くのは spec までで、status は書きません。status に Pod の実際の状態を主に書き込むのは、Pod が動くノードの kubelet です。kubelet 以外が Pod の status を書き換える場合もあります。たとえばノードが止まったりクラスタから切り離されたりすると、Kubernetes はそのノードの Pod の phase を Failed にします。spec には、kube-scheduler がノードを選んで割り当てる(binding)と、Pod を動かすノードの名前(spec.nodeName)が入ります。マニフェストを書く線を除き、図の線はどれも kube-apiserver を通ります。第4回で見たとおり、コンポーネントどうしは kube-apiserver を通してやり取りするからです。

この図は主な書き手だけを描いています。利用者から spec への線はマニフェストを kubectl で送ることを表しますが、図では kubectl そのものを省いています。metadata に書き込む線も省いています(誰が書くかは「metadata:オブジェクトを見分ける情報」で説明します)。作成直後の status の値(phase: Pending など)を誰が入れるかは、このメディアで確かめた範囲の公式ドキュメントには書かれていません。

図の「監視」の線は、kubelet が kube-apiserver に接続して、Pod の変化を見張っていることを表します。第4回で説明した watch の仕組みです。spec.nodeName に自分のノードの名前が入った Pod は、そのノードの kubelet が受け持ちます。kubelet は Pod の spec に書かれたコンテナを動かし、その結果を status に書き込みます。

参考:Objects In Kubernetes | Kubernetes、Pod | Kubernetes API Reference、Pod Lifecycle | Kubernetes、Kubernetes Scheduler | Kubernetes、Communication between Nodes and the Control Plane | Kubernetes、Kubernetes API Conventions(英語。2026年10月時点の内容)

マニフェストと宣言的 API とは

第1回では、Kubernetes に作って管理させるもの(Pod や Deployment など)をリソースと呼び、公式ドキュメントではオブジェクトとも呼ばれると説明しました。この回では、種類(Pod など。マニフェストでは kind に書きます)と、その種類で作った 1 つ 1 つの実体(nginx という名前の Pod)を区別するときに、後者をオブジェクトと書きます。

公式ドキュメントはオブジェクトを「意図の記録(record of intent)」と説明しています。オブジェクトを作ると、Kubernetes はそのオブジェクトが存在し続けるよう絶えず働きます。オブジェクトを作ることは、クラスタのワークロードがどうあってほしいか、つまり望ましい状態を Kubernetes に伝えることです。オブジェクトを作ったり変えたり消したりするには Kubernetes API を使います。kubectl を使うときは、kubectl が代わりに API を呼び出します。

参考:Objects In Kubernetes | Kubernetes

マニフェスト は、作りたいオブジェクトの望ましい状態と、名前などの基本の情報を書いたファイル です。オブジェクトを作る API のリクエストには、これらの情報を JSON にして入れる必要があります。そこで多くの場合、情報をマニフェストに書いて kubectl に渡します。マニフェストは慣例で YAML で書きます(JSON でも書けます)。kubectl は HTTP で API のリクエストを送るときに、マニフェストの中身を JSON などの形式に変換します。

参考:Objects In Kubernetes | Kubernetes

Kubernetes API はこのようなオブジェクトを受け取って保存する API です。公式ドキュメントは、独自のリソースを追加するときの説明の中で、宣言的 API の特徴を挙げています。そのうち、この回に関係するものは次の 4 つです。

  • 比較的小さなオブジェクトの集まりでできている
  • オブジェクトはアプリケーションやインフラの設定を表す
  • オブジェクトに対する主な操作は、作成・読み取り・更新・削除(CRUD)
  • API が表すのは望ましい状態で、正確な今の状態ではない

参考:Custom Resources | Kubernetes

同じページは、宣言的でない API(命令的な API)の兆候として、クライアントが「これをして」と頼み、処理が終わるのを待って結果を受け取る形を挙げています。宣言的 API では、利用者は望ましい状態を宣言し、Kubernetes のコントローラーが今の状態をその望ましい状態に合わせ続けます。このメディアでは宣言的 API を、望ましい状態を書いたオブジェクトを作成・読み取り・更新・削除する形の API と捉えます。

参考:Custom Resources | Kubernetes

なぜマニフェストと宣言的 API が必要なのか

第1回では、docker run でコンテナを 1 つ起動するのは「手順を指示する」やり方で、Deployment のマニフェストで Pod の数を伝えるのは「望ましい状態を宣言する」やり方だと比べました。Kubernetes にも、マニフェストを使わずにコマンドで直接指示するやり方があります。kubectl でオブジェクトを管理する方法は、公式ドキュメントでは次の 3 つに分けられています。

管理の方法例向いている環境(公式ドキュメント)
命令的なコマンド(Imperative commands)kubectl create deployment nginx --image nginx開発のプロジェクト
命令的なオブジェクトの設定(Imperative object configuration)kubectl create -f nginx.yaml、kubectl replace -f nginx.yaml本番のプロジェクト
宣言的なオブジェクトの設定(Declarative object configuration)kubectl apply -f configs/(configs/ はマニフェストを置いたディレクトリの例)本番のプロジェクト

参考:Kubernetes Object Management | Kubernetes

3 つの方法のどれでも、kubectl が Kubernetes API を呼び出して、オブジェクトを作ったり変えたりします。命令的なコマンドの kubectl create deployment も、公式ドキュメントの説明では Deployment のオブジェクトを作るコマンドです。違うのは、作る・置き換えるといった操作を利用者が自分で選ぶかどうかと、設定をファイルに残すかどうかです。

参考:Kubernetes Object Management | Kubernetes、Objects In Kubernetes | Kubernetes

命令的なコマンドでは、クラスタにある今のオブジェクトをコマンドの引数やフラグで直接操作します。始めるときや一度きりの作業には勧められていますが、以前の設定の履歴が残りません。公式ドキュメントは変更をレビューする流れに組み込めないこと、新しいオブジェクトを作るためのひな形にならないことも欠点に挙げています。

設定をマニフェストのファイルに書けば、これらの欠点を補えます。公式ドキュメントによると、ファイルは Git などのバージョン管理に置けて、反映する前に変更をレビューする流れに組み込めます。新しいオブジェクトを作るときのひな形にもなります。その代わり、オブジェクトの構造(スキーマ)を理解し、YAML のファイルを書く手間が要ります。

参考:Kubernetes Object Management | Kubernetes

2 つのファイルを使う方法の違いは、何をするかを利用者が指定するかどうかです。命令的なオブジェクトの設定では、create や replace のように操作を利用者が選びます。宣言的なオブジェクトの設定では、利用者は操作を指定しません。kubectl がオブジェクトごとに、作成・更新・削除のどれが必要かを判断します。kubectl apply がこの方法のコマンドです。公式ドキュメントによると、kubectl apply は違いのある部分だけを patch という API の操作で書き込むので、ほかの書き手がオブジェクトに加えた変更も残ります。ほかの書き手とは、別の利用者や、後で出てくるオートスケーラー(Pod の数などを負荷に応じて自動で変えるコンポーネント)などです。

参考:Kubernetes Object Management | Kubernetes、Objects In Kubernetes | Kubernetes、Kubernetes API Conventions(英語。2026年10月時点の内容)

宣言的 API は第1回で見た自己修復とも結び付いています。望ましい状態がオブジェクトとして保存されているので、コントローラーはいつでもそれを読み、実際の状態との差を埋められます。公式ドキュメントは、クラスタは変化し続けるので安定した状態に至らないこともあり得るが、コントローラーが動いて役に立つ変更を加えられている限り問題ない、と説明しています。Kubernetes の API の規約(開発者向けの文書)も、システムはそれまでの spec がどうだったかにかかわらず、最新の spec に向かって動くとしています。途中の変化を見落としても、最新の spec を目指せばよいということです。例として、Deployment の Pod の数を 3 から 5、5 から 2 と続けて変えた場合を考えます。規約の考え方では、システムは途中の 5 を見落としても、最新の 2 を目指して動けばよいことになります。第1回では、コントローラーが実際の状態を望ましい状態に近づけるこの繰り返しを、調整ループ(Reconciliation Loop)と呼びました。

参考:Controllers | Kubernetes、Kubernetes API Conventions(英語。2026年10月時点の内容)

マニフェストと宣言的 API の仕組み

マニフェストのフィールド

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

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 の値を書く必要があります。クラスタに作ったオブジェクトには、もう 1 つ status が加わります。5 つのフィールドの意味を次の表にまとめます。

フィールド表すもの書く人
apiVersionオブジェクトを作るのに使う Kubernetes API のバージョン利用者
kind作りたいオブジェクトの種類利用者
metadataオブジェクトを一意に見分けるための情報。名前(name)、UID、Namespace(省略できる)など名前などは利用者、UID などは Kubernetes
specオブジェクトの望ましい状態利用者。Kubernetes やほかのコンポーネントが書き足すこともある
statusオブジェクトの実際の状態Kubernetes とそのコンポーネント

参考:Objects In Kubernetes | Kubernetes、ObjectMeta | Kubernetes API Reference

spec と status は、公式ドキュメントでは「ほとんどの」オブジェクトにあるフィールドとされています。どの種類にもあるわけではありません。たとえば設定の値を入れておく ConfigMap(第17回で扱います)には spec も status も無く、代わりに data などのフィールドに中身を書きます。spec の中に書くフィールドも種類ごとに違います。種類ごとのフィールドは API リファレンスで調べられます。

参考:Objects In Kubernetes | Kubernetes、ConfigMap | Kubernetes API Reference

apiVersion と kind が表すもの

Kubernetes API は API グループ という単位に分かれています。apiVersion には API グループとバージョンを グループ/バージョン の形で書きます。ただしコア(core。legacy とも呼ばれます)のグループだけは、グループの名前を書かずにバージョンだけを書きます。この回の Pod と第1回の Deployment を例に、次の表にまとめます。

apiVersionAPI グループ例
v1コアのグループPod、ConfigMap
apps/v1apps のグループDeployment

参考:API Overview | Kubernetes、Pod | Kubernetes API Reference、Objects In Kubernetes | Kubernetes

バージョンの名前は API の安定度を表します。名前に alpha が付くもの(v1alpha1 など)、beta が付くもの(v2beta3 など)、v1 のように数字だけのもの(stable、安定版)の 3 段階です。v1.37 時点の公式ドキュメントによると、組み込みの alpha のバージョンは既定では使えず、kube-apiserver の設定で有効にする必要があります。beta のバージョンも、v1.22 以降に導入されたものは既定では使えません。安定版のバージョンは、Kubernetes のメジャーバージョンが変わらない限り、以降のリリースでも使えます。

参考:API Overview | Kubernetes

kind は種類の名前で、Pod や Deployment のように書きます(API リファレンスでは CamelCase で書くと説明されています)。同じ種類を API の URL では別の名前で表します。Pod なら、kind では Pod、URL では小文字の複数形の pods です。公式ドキュメントは URL で使うほうの名前(pods や services)を resource type と呼びます。このメディアではリソースの種類と訳します。そのリソースの種類の具体的な表現(オブジェクトの構造)を、公式ドキュメントは kind と呼んでいます。kubectl のコマンドの TYPE(第3回)に書く pods は、URL で使うほうの名前にあたります。

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

apiVersion と kind、metadata の Namespace と名前は、API の URL のパスに対応します。以下の図は、さきほどの Pod のマニフェストの各フィールドが、その Pod を表すパスのどこに現れるかを表しています。パスの並びに合わせるため、図ではフィールドの順番をマニフェストと変えています。

マニフェストの apiVersion・kind・metadata と、API のパスの対応

コアのグループのパスは /api/v1 で始まり、apps のような名前の付いたグループのパスは /apis/apps/v1 のように /apis/グループ/バージョン で始まります。そのあとに Namespace、リソースの種類、名前が続きます。公式ドキュメントの例では、Pod を作るときは名前を除いたパス(/api/v1/namespaces/test/pods)に、JSON にした Pod を POST で送っています。公式ドキュメントによると、Kubernetes は Discovery API で、リソースごとに名前、エンドポイントの URL、グループ・バージョン・kind などを公開しています。kubectl はこの情報を使って、クラスタが提供するリソースの一覧を取り出します。kubectl がマニフェストから組み立てるリクエストも、この情報をもとに、このようなパスに送られると考えられます。ただし kubectl が kind からパスを決める細かい手順までは、このメディアで確かめた範囲の公式ドキュメントには書かれていません。

参考:Kubernetes API Concepts | Kubernetes、API Overview | Kubernetes、Object Names and IDs | Kubernetes、The Kubernetes API | Kubernetes

この Pod のマニフェストには metadata.namespace を書いていません。公式ドキュメントによると、Namespace を指定しないと、kubectl はコンテキストに設定された Namespace を対象にします。kind-kind のコンテキストに Namespace が無い場合は default になると考えられ、図ではそのときのパスを示しています。API リファレンスでも、空の Namespace は default と同じ扱いです。

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

公式ドキュメントによると、Kubernetes はオブジェクトを API グループ、リソースの種類、Namespace(Namespace に属する種類の場合)、名前の 4 つで区別します。バージョンは区別に入っていません。公式ドキュメントによると、異なるバージョンは保存された同じデータの別の表し方で、バージョンの間の変換は kube-apiserver が受け持ちます。オブジェクトの中身は、kube-apiserver が etcd に書き込んで保存します。

参考:The Kubernetes API | Kubernetes、Object Names and IDs | Kubernetes

metadata:オブジェクトを見分ける情報

metadata にはオブジェクトを見分けて整理するための情報を書きます。中身の型は API リファレンスで ObjectMeta と呼ばれ、ほかの種類でも同じものを使います。主なフィールドを次の表にまとめます。

フィールド内容書く人
nameオブジェクトの名前。作るときに必須で、作ったあとは変えられない利用者
namespace名前が一意でなければならない範囲。空なら default と同じ。作ったあとは変えられない利用者(省略できる)
labelsオブジェクトを整理し、選び出すためのキーと値の組利用者
annotationsツールなどが任意の情報を入れておくためのキーと値の組利用者やツール
uidオブジェクトを一意に見分ける値Kubernetes(読み取り専用)
creationTimestampオブジェクトが作られた時刻Kubernetes(読み取り専用)
resourceVersionオブジェクトが変わったことを知るための、内部のバージョンKubernetes(読み取り専用)

参考:ObjectMeta | Kubernetes API Reference

API リファレンスでは、uid・creationTimestamp・resourceVersion に「Populated by the system. Read-only.」(システムが値を入れる。読み取り専用)と書かれています。この 3 つはマニフェストには書かず、オブジェクトを作ったときに Kubernetes が入れます。resourceVersion の使われ方は第7回、labels と annotations は第42回、Namespace は第37回で扱います。

参考:ObjectMeta | Kubernetes API Reference

名前は同じ種類のリソースの中で一意です。公式ドキュメントの例では、同じ Namespace に myapp-1234 という名前の Pod は 1 つしか作れませんが、同じ名前の Pod と Deployment は 1 つずつ作れます。多くの種類のリソースでは、名前を DNS のサブドメイン名の決まりで付けます。253 文字以内で、小文字の英数字と -・. だけを使い、英数字で始めて英数字で終える決まりです。一方、UID はクラスタの全期間を通じて、作ったオブジェクトごとに違う値になります。第1回で、同じ名前で作り直した Pod でも metadata.uid は変わると説明したのはこのためです。

参考:Object Names and IDs | Kubernetes

spec と status:望ましい状態と実際の状態

spec にはそのオブジェクトにどうあってほしいか、つまり望ましい状態を書きます。spec を持つ種類では、作るときに spec を書く必要があります。status は、Kubernetes とそのコンポーネントが書き込んで更新する、実際の状態です。コントロールプレーンは、オブジェクトの実際の状態が望ましい状態に一致するよう、継続して管理します。

参考:Objects In Kubernetes | Kubernetes

spec には、利用者が書いた値だけが入るわけではありません。Kubernetes の API の規約は、spec を望ましい状態の完全な記述と定めています。そこには利用者が書いた設定に加えて、システムが入れた既定値や、作ったあとにほかのコンポーネントが入れたり変えたりした値も含まれます。規約が挙げるコンポーネントの例は、スケジューラーと、負荷に応じて数などを変えるオートスケーラーです。規約は status については、実際の状態を最後に観測した結果を書くものとしています。

参考:Kubernetes API Conventions(英語。2026年10月時点の内容)

同じ規約は、オブジェクトを作る POST と、オブジェクトを置き換える PUT のリクエストでは status の値を無視しなければならない、としています。システムのコンポーネントが status を更新するためには、/status という別のパス(サブリソース)を用意する決まりです。Pod の API リファレンスにも、/api/v1/namespaces/{namespace}/pods/{name}/status に対する操作(Read Status、Replace Status、Patch Status)が、Pod そのものの操作とは別に載っています。そのため、マニフェストに status を書いても、利用者の作成や更新では使われないと考えられます。

参考:Kubernetes API Conventions(英語。2026年10月時点の内容)、Kubernetes API Concepts | Kubernetes、Pod | Kubernetes API Reference

Pod について、誰がどのフィールドに書き込むのかを次の表にまとめます。値は v1.37 時点の API リファレンスと公式ドキュメントに基づきます。

書き込むもの場所主なフィールドと値
利用者(マニフェスト)speccontainers の name・image・ports
Kubernetes(書かなかったフィールドの既定値)specrestartPolicy: Always、dnsPolicy: ClusterFirst、terminationGracePeriodSeconds: 30、serviceAccountName: default、コンテナの imagePullPolicy: IfNotPresent(nginx:1.14.2 のように latest 以外のタグを指定した場合)
Kubernetes(作ったとき)metadatauid、creationTimestamp、resourceVersion
kube-scheduler の割り当て(binding)の結果specnodeName(Pod を動かすノードの名前)
ノードの kubeletstatusphase、conditions、startTime など

参考:Pod | Kubernetes API Reference、Service Accounts | Kubernetes、ObjectMeta | Kubernetes API Reference、Pod Lifecycle | Kubernetes

既定値のそれぞれの意味は後の回で扱います。この回では、書かなかったフィールドにも値が入ることだけ押さえれば十分です。

spec.nodeName は、API リファレンスでは「Pod がスケジュールされたノード」を表すフィールドです。値が空のあいだ、その Pod は kube-scheduler がノードを選ぶ対象になります。値が入ると、そのノードの kubelet が Pod のライフサイクルを受け持ちます。第4回で見たように、kube-scheduler はノードを選んだ結果を binding で kube-apiserver に伝えます。公式ドキュメントは Pod を特定のノードに割り当てることを binding と呼んでいます。スケジューラーが割り当てたノードが、このフィールドに表れます。kube-apiserver の中でどの処理がこのフィールドに値を書き込むかは、このメディアで確かめた範囲の公式ドキュメントには書かれていません。

参考:Pod | Kubernetes API Reference、Kubernetes Scheduler | Kubernetes、Pod Lifecycle | Kubernetes、Kubernetes API Conventions(英語。2026年10月時点の内容)

status のフィールドでは、phase が Pod の今の段階を一言で表します。値は次の 5 つです。

phase の値意味
Pendingクラスタに受け付けられたが、まだ動く準備ができていないコンテナがある。ノードが決まるまでの時間と、イメージをダウンロードする時間を含む
Runningノードに割り当てられ、すべてのコンテナが作られた。少なくとも 1 つのコンテナが動いているか、起動・再起動の途中
Succeededすべてのコンテナが成功して終了し、再起動されない
Failedすべてのコンテナが終了し、少なくとも 1 つが失敗して終了した
Unknown何らかの理由で Pod の状態を取得できない。多くはノードとの通信の問題

参考:Pod Lifecycle | Kubernetes

v1.37 時点の API リファレンスでは、Unknown は「2015 年から設定されていない」として非推奨(Deprecated)とされています。

参考:Pod | Kubernetes API Reference

status には、ほかに次のようなフィールドがあります。

  • conditions:Pod が通った段階ごとの状態。PodScheduled、Initialized、ContainersReady、Ready などがあり、それぞれ True・False・Unknown のどれか
  • hostIP:Pod が割り当てられたノードの IP アドレス。Pod がまだ始まっていなければ空
  • podIP:Pod に割り当てられた IP アドレス。まだ割り当てられていなければ空
  • startTime:kubelet がその Pod を受け付けた時刻
  • containerStatuses:Pod の中のコンテナごとの状態

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

公式ドキュメントでは、kubelet が Pod の conditions を設定したり、phase を変えたりする様子が説明されています。hostIP や podIP を書き込むコンポーネントは、API リファレンスには明記されていません。ただし hostIP の説明には、kubelet に問題のあるノードに割り当てられた Pod では、ノードが決まっていても hostIP が更新されないことがある、と書かれています。Pod の段階と再起動の仕組みは第9回で詳しく扱います。

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

マニフェストを渡してから status が埋まるまで

ここまでの内容を、Pod のマニフェストを kubectl apply で渡してから status が埋まるまでの大まかな流れとして、次の表にまとめます。

順番担当すること
1kubectlマニフェストを JSON などに変換し、kube-apiserver にリクエストを送る
2kube-apiserverフィールドを検査し、オブジェクトを etcd に保存する。この時点で spec が読めるようになる
3kube-schedulerノードが決まっていない Pod を見つけてノードを選び、binding で kube-apiserver に伝える
4選ばれたノードの kubeletPod を受け持ち、コンテナランタイムにコンテナを動かしてもらう
5kubeletPod の実際の状態を status に書き込む(phase が Pending から Running になる、など)

参考:Objects In Kubernetes | Kubernetes、Kubernetes API Concepts | Kubernetes、The Kubernetes API | Kubernetes、Kubernetes Scheduler | Kubernetes、Pod Lifecycle | Kubernetes

Kubernetes の API の規約によると、オブジェクトを POST や PUT で送ると、spec はすぐに更新されて読めるようになります。そのあと時間をかけて、システムが status を spec に合わせていきます。つまり、kubectl apply が成功しても、それは望ましい状態を受け付けたという意味で、コンテナが動いたことまでは表しません。動いたかどうかは status で確かめます。後半の「手元で試す」では、この時間差を作成直後と数秒後の status で見比べます。

参考:Kubernetes API Conventions(英語。2026年10月時点の内容)、Pod Lifecycle | Kubernetes

手順 2 のフィールドの検査(validation)では、フィールドの型が確かめられます。たとえば数値のフィールドに文字列は書けず、必須のフィールドを省くとエラーになります。API の構造に無いフィールドの扱いは、検査の厳しさ(Ignore・Warn・Strict)によって変わります。v1.37 時点の公式ドキュメントによると、kubectl の既定は --validate=true で、これは Strict にあたります。Strict では、知らないフィールドや重複したフィールドがあるとリクエストは拒否されます。

参考:Kubernetes API Concepts | Kubernetes、Objects In Kubernetes | Kubernetes

手元で試す

ここまでの内容を、手元の kind のクラスタで試す手順を示します。kubectl explain でフィールドの意味を確かめ、Pod を作って spec と status を作成直後と数秒後で比べます。コマンドは 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回の使い分けのとおり、ノードの数に関係しない仕組みを試すからです。

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

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

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

console
$ kind get clusters

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

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 になっていなければ、少し待ってからもう一度実行します。NAME 列に表示されたノードの名前は、あとで Pod の spec.nodeName と見比べるので控えておきます。

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

kubectl explain でフィールドの意味を確かめる

第3回で見たとおり、kubectl explain はフィールドの説明を、接続先のクラスタから OpenAPI の形式で取り出して表示します。まず、Pod の一番上の階層のフィールドを調べます。

console
$ kubectl explain pods --context kind-kind

Pod の説明と、Pod のフィールドの一覧が表示されます。一覧の中から、apiVersion・kind・metadata・spec・status の 5 つを探してください。v1.37 時点の API リファレンスでは、spec は「Specification of the desired behavior of the pod.」(Pod の望ましい振る舞いの仕様)と説明されています。status は「Most recently observed status of the pod. This data may not be up to date. Populated by the system. Read-only.」(最後に観測した Pod の状態。最新とは限らない。システムが値を入れる。読み取り専用)です。explain は同じ API の仕様から説明を取り出すので、同じ趣旨の説明が表示されると考えられます。

参考:kubectl explain | Kubernetes、Pod | Kubernetes API Reference

次に、Kubernetes が値を入れるフィールドと、kube-scheduler が値を入れるフィールドを調べます。

console
$ kubectl explain pods.metadata.uid --context kind-kind
$ kubectl explain pods.spec.nodeName --context kind-kind

metadata.uid の説明には「Populated by the system. Read-only.」の一文があるはずです。この一文は、利用者がこのフィールドを書かず、Kubernetes が値を入れることを表します。spec.nodeName の説明には、空なら Pod がスケジューラーのノード選びの対象になること、値が入るとそのノードの kubelet が Pod を受け持つことが書かれているはずです。spec の中にも、利用者以外が書き込むフィールドがあることがわかります。

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

続けて、status の中の phase を調べます。

console
$ kubectl explain pods.status.phase --context kind-kind

Pending・Running・Succeeded・Failed・Unknown の 5 つの値と、それぞれの意味が表示されるはずです。「spec と status」の節の表と見比べてください。Unknown には、API リファレンスと同じく非推奨(Deprecated)の注記が表示されることがあります。

参考:Pod | Kubernetes API Reference

最後に、spec を持たない種類も調べます。

console
$ kubectl explain configmaps --context kind-kind

ConfigMap のフィールドの一覧には spec と status が無く、代わりに data などがあるはずです。spec と status は「ほとんどの」オブジェクトにあるフィールドだということを確かめられます。

参考:ConfigMap | Kubernetes API Reference

Pod を作って spec と status を比べる

「マニフェストのフィールド」で引用した 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

同じ名前の Pod がすでにあると、作成直後の様子は見られません。前の回のクラスタを使い続けている場合は、先に Pod を一覧して確かめます。

console
$ kubectl get pods --context kind-kind

一覧の NAME 列に nginx があれば、この回の「片付け」の kubectl delete -f simple-pod.yaml --context kind-kind で消してから進みます。

参考:kubectl get | Kubernetes

kubectl apply で Pod を作り、すぐに続けて、作った Pod を YAML の形式で nginx-first.yaml に書き出します。2 つのコマンドを && でつないで、間を空けずに実行するためです。

console
$ kubectl apply -f simple-pod.yaml --context kind-kind && kubectl get pod nginx -o yaml --context kind-kind > nginx-first.yaml

公式ドキュメントの Deployment の例では、kubectl apply の出力は次のとおりです。

deployment.apps/nginx-deployment created

参考:Objects In Kubernetes | Kubernetes

Pod を作った今回は、pod/nginx と created を含む 1 行が表示されると考えられます。そのあとの kubectl get の出力は画面には出ず、nginx-first.yaml に書き出されます。-o yaml は、kube-apiserver から取り出したオブジェクトを YAML の形式で表示する指定です(第3回)。

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

書き出したファイルを表示します。

console
$ cat nginx-first.yaml

自分で書いた 10 行のマニフェストより、ずっと多くの行が並んでいるはずです。見るところを一番上の階層のフィールドごとに次の表にまとめます。

フィールド見るところ
metadata書いた name のほかに、uid・creationTimestamp・resourceVersion と、namespace: default がある
spec書いた containers のほかに、restartPolicy・dnsPolicy・serviceAccountName などの既定値がある
statusマニフェストに書いていないのに、このフィールドがある。phase の値を見る

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

表に無いフィールドもたくさん並んでいるはずです。それらも書いていないのに入ったものなので、Kubernetes が入れたものと考えられます。この回では、1 つずつの意味は気にしなくて構いません。

マニフェストに Namespace を書いていないので、kubectl は kind-kind のコンテキストに設定された Namespace を使います。そのコンテキストに Namespace が無ければ、default が使われると考えられます。コンテキストに Namespace があるかは、第3回と同じく kubectl config view を実行し、kind-kind のコンテキストに namespace の行があるかで確かめられます。API リファレンスによると、空の Namespace は default と同じ扱いです。

参考:Command line tool (kubectl) | Kubernetes、kubectl config view | Kubernetes、ObjectMeta | Kubernetes API Reference

metadata.annotations には kubectl.kubernetes.io/last-applied-configuration というアノテーションもあるはずです。kubectl apply で作ったときに kubectl が付けるもので、中身は作るのに使ったマニフェストです。公式ドキュメントの例では、マニフェストを JSON の形にした文字列が入っています。このアノテーションの役割は第7回で扱います。

参考:Declarative Management of Kubernetes Objects Using Configuration Files | Kubernetes

作成直後の status は、まだ埋まりきっていないはずです。phase が Pending で、podIP などがまだ無いことが多いと考えられます。Pending には、ノードが決まるまでの時間と、イメージをダウンロードする時間が含まれるからです。ただし、どこまで書き込まれているかはタイミングで変わります。そのノードに同じイメージがすでにあれば、作成直後でも Running になっていることがあります。spec.nodeName も同じで、1 回目の時点ですでに入っていることも、まだ無いこともあり得ます。

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

次に、必要なフィールドだけを取り出して、数秒おきに何度か表示します。-o jsonpath は、{} で囲んだ式で JSON の中のフィールドを指定して取り出す出力の形式です。ここでは spec.nodeName、status.phase、status.podIP を 1 行ずつ表示します。

console
$ kubectl get pod nginx -o jsonpath='{.spec.nodeName}{"\n"}{.status.phase}{"\n"}{.status.podIP}{"\n"}' --context kind-kind

参考:JSONPath Support | Kubernetes

1 行目がノードの名前、2 行目が phase、3 行目が Pod の IP アドレスです。値がまだ無いフィールドがあっても、エラーにはなりません。kubectl get の --allow-missing-template-keys の既定が true で、jsonpath の式のフィールドが無いときのエラーを無視するからです。値が無いフィールドの行は、空になると考えられます。何度か実行するうちに、1 行目に kubectl get nodes で控えたノードの名前が、2 行目に Running が、3 行目に IP アドレスが表示されるはずです。WSL を使わずに Windows で実行する場合は、引用符の付け方が違うので、公式ドキュメントの JSONPath のページの注意を見てください。

参考:JSONPath Support | Kubernetes、kubectl get | Kubernetes、Pod | Kubernetes API Reference、Pod Lifecycle | Kubernetes

1 分ほど待っても Pending のままなら、Pod を詳しく表示して原因を探します。

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

表示の末尾近くの Events: の欄に、その Pod について起きた出来事(第3回で見たイベント)が並びます。spec.nodeName が空のまま、つまりノードに割り当てられないまま止まっている場合は、この表示にスケジューラーからの理由のメッセージがあるはずだと公式ドキュメントは説明しています。spec.nodeName が入っているのに Pending のままなら、イメージのダウンロードに時間がかかっていることや、失敗していることなどが考えられます。Pending にはイメージをダウンロードする時間も含まれるからです。公式ドキュメントは、ノードに割り当てられたのにコンテナが動けない Waiting の状態について、最もよくある原因はイメージの取得の失敗だとしています。ここでの Waiting はコンテナの状態で、Pod の phase ではありません。原因の調べ方は第41回で扱います。

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

2 行目が Running になったら、もう一度 YAML で書き出し、1 回目と比べます。diff は 2 つのファイルの違う行を表示するコマンドで、macOS や Linux には通常入っています。一般的に、1 つ目のファイルにだけある行は先頭に < が、2 つ目のファイルにだけある行は先頭に > が付いて表示されます。

console
$ kubectl get pod nginx -o yaml --context kind-kind > nginx-later.yaml
$ diff nginx-first.yaml nginx-later.yaml

違う行の多くは status の中にあるはずです。phase が Running になり、1 回目に無かった hostIP・podIP が加わります。startTime は kubelet が Pod を受け付けた時刻で、イメージを取得する前に入るので、1 回目にすでにあることも、2 回目に加わることもあります。conditions でも、Ready などの項目が True になっているはずです。containerStatuses のコンテナの状態も変わっているはずです。1 回目に spec.nodeName が無かった場合は、2 回目にノードの名前が加わります。metadata.resourceVersion も変わっていると考えられます。API リファレンスによると、resourceVersion はオブジェクトが変わったことを知るために使える値で、今回は status が変わっているからです。

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

一方、自分で書いた spec.containers の name・image・ports は、2 つのファイルで変わっていないはずです。利用者が書いた望ましい状態はそのままで、Kubernetes のコンポーネントが実際の状態を status に書き足していったことになります。1 回目ですでに Running だった場合は、違いが少なくなります。その場合も、マニフェストに書いていない status が最初からあることは確かめられます。

kubectl get pod nginx --context kind-kind の STATUS 列にも、Running などが表示されます。ただし公式ドキュメントによると、この列は人が読みやすいように kubectl が表示するもので、phase そのものではありません。たとえば削除中の Pod では、phase の値には無い Terminating がこの列に表示されることがあります。phase を確かめるときは、上のように status.phase を取り出します。

参考:Pod Lifecycle | Kubernetes

kubectl get の -o yaml の表示には、metadata.managedFields が含まれません。--show-managed-fields の説明が「true なら managedFields を残す」なので、付けなければ表示から除かれます。managedFields は、どの書き手がどのフィールドを管理しているかの記録で、API リファレンスでは利用者がふつう設定したり理解したりする必要はないとされています。

参考:kubectl get | Kubernetes、ObjectMeta | Kubernetes API Reference

API のパスで同じ Pod を取り出す

「apiVersion と kind が表すもの」の図のパスを使って、同じ Pod を取り出します。--raw は指定したパスへのリクエストを、kubeconfig の接続先にそのまま送るフラグです。

console
$ kubectl get --raw /api/v1/namespaces/default/pods/nginx --context kind-kind

公式ドキュメントによると、Kubernetes API は既定で JSON の形式でオブジェクトを返します。表示は JSON の形式で、kind が Pod、apiVersion が v1 の項目を含むはずです。改行の無い 1 行の長い JSON で表示されることもあると考えられるので、その中から "kind" と "Pod" が並ぶ部分を探してください。中身は -o yaml で見たものと同じ Pod です。--raw は応答をそのまま表示するので、-o yaml では除かれていた managedFields も含まれると考えられます。マニフェストの apiVersion(v1)、Namespace(default)、リソースの種類(pods)、名前(nginx)が、パスの中に並んでいることを確かめてください。

参考:kubectl get | Kubernetes、Kubernetes API Concepts | Kubernetes

片付け

作った Pod を、マニフェストを指定して削除します。

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

kubectl delete -f は、ファイルに書かれた種類と名前のオブジェクトを削除します。kubectl delete は既定では、オブジェクトが消えるまで待ってから終わります。Pod には終了までの猶予の時間(既定では 30 秒)があるので、終わるまで少しかかることがあります。そのあとの kubectl get pods の一覧に nginx が無ければ、削除できています。

kubectl apply で作ったオブジェクトを kubectl delete -f で消すことは、「注意点」の「管理の方法を混ぜない」には当たりません。公式ドキュメントの宣言的な管理の手順でも、kubectl apply で管理しているオブジェクトを消す方法として、kubectl delete -f <ファイル> を勧めています。何を消すのかがはっきりしていて、意図しないものを消しにくいからです。

参考:kubectl delete | Kubernetes、Kubernetes Object Management | Kubernetes、Pod | Kubernetes API Reference、Declarative Management of Kubernetes Objects Using Configuration Files | Kubernetes

書き出した 2 つのファイルが要らなければ消します。

console
$ rm nginx-first.yaml nginx-later.yaml

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

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

注意点

マニフェストを書き始めるときにつまずきやすい点と、後から変えられない点、バージョンで変わる点を、次の表にまとめます。

項目内容
status は書かないstatus は Kubernetes のコンポーネントが書く。API の規約では、作成や置き換えのリクエストは status の値を無視することになっている
apply の成功は「受け付けた」という意味spec はすぐに保存されるが、コンテナが動くのはそのあと。動いたかどうかは status で確かめる
綴りを間違えたフィールドはエラーになるv1.37 時点の kubectl の既定(--validate=true)では、API の構造に無いフィールドがあるとリクエストが拒否される。型が合わない値も、検査の厳しさに関係なくエラーになる
name と namespace は後から変えられないAPI リファレンスで「Cannot be updated」とされている。名前を変えたいときは、新しい名前でオブジェクトを作り直す
apiVersion は古くなることがあるたとえば Deployment の extensions/v1beta1・apps/v1beta1・apps/v1beta2 は v1.16 から提供されていない。古い記事のマニフェストを使うときは、今の apiVersion(Deployment なら apps/v1)か確かめる
管理の方法を混ぜない公式ドキュメントは、1 つのオブジェクトは 1 つの管理の方法だけで扱うよう警告している。混ぜたときの動きは定められていない
STATUS 列は phase ではないkubectl get pods の STATUS 列は kubectl の表示用の項目。Terminating などの、phase に無い値も表示される

参考:Kubernetes API Conventions(英語。2026年10月時点の内容)、Objects In Kubernetes | Kubernetes、Kubernetes API Concepts | Kubernetes、ObjectMeta | Kubernetes API Reference、Deprecated API Migration Guide | Kubernetes、Kubernetes Object Management | Kubernetes、Pod Lifecycle | Kubernetes

提供されなくなった API のバージョンからの移し方は、公式ドキュメントの Deprecated API Migration Guide にまとまっています。そこでは、既存のマニフェストを新しいバージョンに書き換える kubectl convert も紹介されています。ただし kubectl convert は kubectl に既定では入っていないプラグインで、別に入れる必要があります。

参考:Deprecated API Migration Guide | Kubernetes

関連記事

spec と status の差を埋めるコントローラーの繰り返し(調整ループ)については、以下の記事で解説しています。

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

kubectl apply と kubectl edit でオブジェクトを更新したときに、resourceVersion や last-applied-configuration がどう変わるかについては、以下の記事で解説しています。

基本仕様 第7回 kubectl apply と kubectl edit の違いマニフェストを渡して更新する kubectl apply と、クラスタのオブジェクトをエディタで直接書き換える kubectl edit の違いを図で説明します。更新の流れ、last-applied-configuration、resourceVersion の役割を押さえ、kind のクラスタで 2 つのコマンドで Deployment を更新して、値の変化を比べる手順を紹介します。

この回で直接作った Pod そのものの仕組みについては、以下の記事で解説しています。

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

Kubernetes 基本仕様の目次へ