Kubernetesを学ぶ:6段階ロードマップ

この記事にはアフィリエイト広告が含まれています。 冒頭まとめ Kubernetesのエラーを検索して1件ずつ直しているのに、翌日は別のエラーで止まる。この繰り返しから抜けるには、覚える順序を変える必要があります。 Kubernetesのエラーの多くは、4つの境界のどこかで起きています。宣言した状態と実際の状態の境界、コントロールプレーンとノードの境界、Podの内と外の境界、そしてPodの寿命とデータの寿命の境界です。エラー文やイベントはこの境界のどれで止まったかを示していますが、境界の存在を知らないと文言が読めません。 Dockerとの最大の違いはここにあります。Dockerでは実行した命令がそのまま結果になりますが、Kubernetesでは「こうあってほしい」という宣言を出し、それを実現しようとする過程が延々と続きます。したがってエラーは、失敗した瞬間ではなく、実現できないまま繰り返している状態として現れます。 学ぶ順序は、Podとコンテナ、Deploymentと宣言、Serviceとネットワーク、設定とデータ、スケジューリングとリソース、ログとトラブルシューティングの6段階です。各段階には「次へ進む目安」を置きました。飛ばした段階は、後の段階のエラーとして別の顔で現れます。 個別に直すだけでは理解しにくい理由 検索で見つかる対処は、多くの場合その環境で有効だった手順です。なぜ有効だったかは書かれていないことがあります。 たとえば、Podが起動しないときに kubectl delete pod を実行したら直った、という手順があります。Deploymentの管理下にあるPodは削除すると作り直されるので、一時的な不具合であれば確かに解消します。しかし原因がマニフェストの側にあれば、作り直されたPodも同じ理由で止まります。Podが誰に管理されているかを知らないと、この区別ができません。 同じことがネットワークでも起きます。Serviceの port と targetPort を同じ値に揃えたら繋がった、という手順は、どちらがService側でどちらがコンテナ側かを知らなければ再現できません。 エラー文とイベントも同じです。Kubernetesの表示は、どの部品が判断したのかを示しています。スケジューラが置き場所を決められないのか、kubeletがイメージを取得できないのか、コンテナの中のプロセスが落ちているのかで、直す場所が変わります。この区別は、次に説明する全体像を知っていれば読み取れます。 最初に理解するべきKubernetesの全体像 先に部品の関係を押さえます。ここを飛ばすと、後のすべての段階で判断がぶれます。 公式ドキュメントによれば、Kubernetesクラスターはコントロールプレーンと1つ以上のワーカーノードで構成されます。コントロールプレーン側には、KubernetesのHTTP APIを公開する中核サーバーである kube-apiserver、APIサーバーの全データを保持するキーバリューストアの etcd、まだノードに割り当てられていないPodを探して適切なノードへ割り当てる kube-scheduler、APIの振る舞いを実装するコントローラーを動かす kube-controller-manager があります。ノード側には、Podとそのコンテナが動いていることを保証する kubelet、Serviceを実装するネットワーク規則を維持する kube-proxy、コンテナの実行を担うコンテナランタイムがあります(Cluster Architecture)。 この構造から、エラーの読み分けが決まります。kubectl はAPIサーバーへ要求を送るだけの道具です。マニフェストを適用した時点で成功と表示されても、それは「宣言が受け付けられた」という意味であり、動き出したという意味ではありません。実際に動くかどうかは、その後にスケジューラとkubeletが決めます。 したがってKubernetesの調査は、常に2段構えになります。宣言は正しく登録されたか。そしてその宣言を実現しようとした過程のどこで止まったか。前者は kubectl get で、後者は kubectl describe のイベント欄で確認します。 まずは手元の環境が動いているかを確認してください。 kubectl cluster-info kubectl get nodes ノードが Ready でなければ、この先のPodはどれも起動しません。この時点で次へ進んでも、以降のコマンドはすべて同じ理由で止まります。 学習ステップ1:Podとコンテナ 何を理解する段階か:Podが何の単位なのか、そしてコンテナとどう違うのかです。 なぜエラー解決に必要か:Kubernetesのエラーの大半はPod単位で現れます。Podの状態欄とコンテナの状態欄が別々にあることを知らないと、どちらの情報を読んでいるのか分からなくなります。 最低限覚える概念:公式ドキュメントによれば、PodはKubernetesで作成・管理できる最小のデプロイ単位で、1つ以上のコンテナのグループです。ストレージとネットワークの資源を共有し、コンテナをどう動かすかの仕様を持ちます。Podの中身は常に同じ場所に配置され、同時にスケジュールされ、共有された文脈で動きます(Pods)。 つまりPodは、複数のコンテナをまとめて1台の論理的なホストのように扱う入れ物です。同じPodの中のコンテナは同じネットワーク名前空間を共有するため、互いに localhost で通信できます。別のPodには届きません。 実際に試すコマンド: # Pod を一覧する kubectl get pods # 状態とノードと再起動回数まで表示する kubectl get pods -o wide # Pod の詳細とイベントを確認する(最も重要) kubectl describe pod <Pod名> # Pod 内のコンテナでコマンドを実行する kubectl exec -it <Pod名> -- sh # 複数コンテナがある場合はコンテナを指定する kubectl exec -it <Pod名> -c <コンテナ名> -- sh kubectl describe の出力は上半分が宣言された内容、下半分の Events が実現しようとした過程です。エラーの理由はほぼ常に下半分にあります。 ...

2026年8月9日 · ErrorLog

Kubernetes の ErrImagePull:原因と解決策

冒頭まとめ 同じ Pod を見ているのに、表示が ErrImagePull になったり ImagePullBackOff になったりする。この入れ替わりを原因の変化だと受け取ると、調べる方向を誤ります。 2つは原因の違いではありません。同じ失敗を、時間軸の別の地点から呼んだ名前です。kubelet は取得を求められると、まず待機の途中かどうかを確かめます。待機中なら取得を行わず ImagePullBackOff を返します。待機が明けていれば実際に取得を試み、失敗したときに ErrImagePull を返します。つまり前者は次の試行を待っている時間帯、後者は試して失敗した瞬間です。 したがって、どちらが表示されているかは原因を何も語りません。実際、この入れ替わりは利用者にとって分かりにくいと開発側も認めており、待機中の表示に前回の失敗理由を残す変更が v1.32 で入りました。 もう1つ、名前そのものの意味も押さえてください。ErrImagePull は取得失敗の総称ではありません。実装はレジストリに届かない場合と署名の検証に失敗した場合を先に切り分け、そのどちらでもない残り全部を ErrImagePull にしています。分類できなかった、という意味の名前です。 だから原因は名前ではなくメッセージ本文にあります。実際に取得を試みた瞬間に出る警告のイベントだけが、コンテナの実行基盤が返した文言をそのまま載せています。ここを取り逃がすと、手がかりが無くなります。 エラーの概要 kubectl describe pod のイベントは、失敗が続くと次の並びになります。 Normal Pulling 2m kubelet Pulling image "example.com/app:v1" Warning Failed 2m kubelet Failed to pull image "example.com/app:v1": rpc error: code = NotFound desc = ... Warning Failed 2m kubelet Error: ErrImagePull Normal BackOff 95s kubelet Back-off pulling image "example.com/app:v1" Warning Failed 95s kubelet Error: ImagePullBackOff Failed という理由が2行出ますが、意味が違います。1行目は実際に取得を試みて返ってきた文言で、原因はここにしかありません。2行目は状態の名前を告げているだけです。この違いは実装の作りから来ています。取得の失敗は Failed to pull image %q: %v の形で記録され、状態の名前は別の箇所から Error: %v の形で記録されます。 ...

2026年8月7日 · ErrorLog

Kubernetes の PVC が Pending:原因と解決策

冒頭まとめ PVC(PersistentVolumeClaim、ストレージの割り当てを求めるオブジェクト)が Pending のままになったとき、まず容量や設定ファイルを読み返す人が多くいます。順序としては後回しでかまいません。先に読むべきなのは kubectl describe pvc の Events に出る Reason の1語です。 理由は実装にあります。Kubernetes の制御側は、未結合の要求を1か所で3つの経路に振り分けています。結合を遅らせる設定で誰も使っていない場合、クラス名が指定されていて動的な作成に進む場合、そのどちらでもない場合です。この3分岐がそのまま Reason になるため、Reason を見れば自分がどの経路にいるかが確定します。 分かれ方は5通りです。WaitForFirstConsumer と WaitForPodScheduled は待機、ExternalProvisioning と ProvisioningFailed は動的な作成、FailedBinding は既存の領域との突き合わせで、それぞれ直す場所が違います。 最も見落とされるのが2番目です。WaitForPodScheduled が出ているなら、待たせているのは PVC ではありません。それを使う Pod が配置できずに止まっています。PVC の定義を読み直しても原因は出てきません。 WaitForFirstConsumer も異常ではありません。公式ドキュメントは、この設定が Pod ができるまで結合と作成を意図的に遅らせるものだと説明しています。Pending の表示だけを見て設定を書き換えると、かえって配置できない Pod を作ることになります。 エラーの概要 一覧では、状態が Pending のまま止まり、割り当て先の欄が空になります。 NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE data-pvc Pending standard 6m41s この Pending は、実装では要求の段階を表す3つの値のうちの1つです。Pending(まだ結合されていない)、Bound(結合済み)、Lost(結合していた領域が失われた)の3つが定義されています。つまり Pending 自体は失敗ではなく、結合がまだ済んでいないという事実だけを示します。 理由は Events に出ます。表示例は次のようになります。 Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal WaitForFirstConsumer 20s (x6 over 87s) persistentvolume-controller waiting for first consumer to be created before binding 出所は persistentvolume-controller です。このコードは未結合の要求を3つに振り分けます。第一に、結合を遅らせる設定で、まだ配置の判断が渡ってきていない場合。第二に、クラス名が空でない場合。第三に、そのどちらでもない場合です。1番目からは WaitForFirstConsumer または WaitForPodScheduled、2番目からは ExternalProvisioning・ProvisioningFailed・ProvisioningSucceeded、3番目からは FailedBinding が出ます。 ...

2026年8月7日 · ErrorLog

Kubernetes FailedCreatePodSandbox:原因と解決策

冒頭まとめ FailedCreatePodSandbox は、kubelet が Pod の sandbox(ネットワーク名前空間や pause コンテナといった、コンテナ起動前の土台)を作成できなかったときに記録される警告イベントです。Pod は ContainerCreating のまま止まり、kubelet はリトライを繰り返します。 原因はほぼ次の3方向に分かれます。 CNI プラグインまたは CNI 設定の不整合で、Pod のネットワーク設定(IP 割り当てを含む)に失敗している container runtime が sandbox image(pause image)を取得・起動できず、sandbox コンテナを作れない ノード側の状態(ディスク、iptables/sysctl、カーネルモジュール、runtime プロセス)が壊れている 調査の出発点は「イベント本文の desc = 以降に書かれた、container runtime から返った実メッセージ」です。ここに cni / network / image / no space left on device のどの語が出ているかで、上の1〜3のどれを追うべきかがほぼ決まります。次に「1ノードだけの問題か、クラスタ全体か」を確認すると、ノード修復かクラスタ設定修正かの判断が付きます。 エラーの概要 これは HTTP ステータスではなく kubelet のイベント理由です FailedCreatePodSandbox はエラーコードではなく、kubelet が Pod に対して発行する Event の reason です。kubectl describe pod の Events 欄や kubectl get events に現れます。 実際にクラスタ上で出力される文字列は FailedCreatePodSandBox(Box の B が大文字) です。ログやイベントを検索するときは大文字小文字を区別しない検索(grep -i)を使うと取りこぼしが減ります。 ...

2026年8月5日 · ErrorLog

Kubernetes Init:CrashLoopBackOff:原因と解決策

冒頭まとめ Init:CrashLoopBackOff は、Pod の init container が失敗して終了し、kubelet による再起動が繰り返されてバックオフ待ちに入っている状態を示します。Kubernetes 公式ドキュメントでは、init container は必ず完了まで実行され、次の init container が始まる前に成功して終了する必要があり、init container が失敗した場合は kubelet が成功するまでその init container を繰り返し再起動すると説明されています。つまりこのエラーが出ている間、通常(アプリ)コンテナは一度も起動していません。 調査の出発点は次の 2 つです。 kubectl describe pod <pod-name> と status.initContainerStatuses で、どの init container が止まっているかを特定する。 kubectl logs <pod-name> -c <init-container> --previous で、直前に終了したインスタンスの終了理由を確認する。 本体コンテナの CrashLoopBackOff と混同すると調査対象がずれます。Init: の接頭辞が付いている間は、修正対象は init container 側です。 エラーの概要 Init:CrashLoopBackOff は Pod の STATUS 列に表示される文字列で、Pod の初期化フェーズで失敗が繰り返されていることを表します。 公式ドキュメントで確認できる init container の性質は次のとおりです。 init container は通常のコンテナとほぼ同じですが、常に完了まで実行される点が異なります。各 init container は、次の init container が起動する前に成功して完了しなければなりません。 init container が失敗した場合、kubelet はそれが成功するまで繰り返し再起動します。ただし Pod の restartPolicy が Never で、起動中に init container が失敗した場合は、Kubernetes は Pod 全体を失敗として扱います。 Pod の STATUS は初期化の進み方を示します。Debug Init Containers では、たとえば Init:1/2 は 2 つある init container のうち 1 つが成功して完了したことを示すと説明されています。 近い表示との違いを整理します。 ...

2026年8月5日 · ErrorLog

Kubernetes RunContainerError:原因と解決策

冒頭まとめ RunContainerError は、HTTPステータスコードではなく、Pod内のコンテナ状態に出る waiting.reason です。Podはノードに割り当てられ、Pod sandboxも作られた後、kubeletがcontainer runtimeへコンテナ起動を依頼した段階で失敗しています。 State: Waiting Reason: RunContainerError Message: <container runtime が返した実メッセージ> ここで重要なのは、RunContainerError という文字だけでは原因が決まらないことです。原因は隣にある Message、直近のEvents、そして同じノード上の他Podの状態から切り分けます。 まず次の4つを分けてください。 表示されているreasonが本当に RunContainerError なのか。 messageがワークロード設定の問題を示しているのか。 volume、権限、セキュリティ設定など、Pod定義とノード条件の組み合わせで失敗しているのか。 containerd、CRI-O、runc、cgroup、ディスクなど、ノード側runtimeの問題なのか。 kubectl logs が空でも不思議ではありません。プロセスがまだ開始できていないため、アプリケーションログへ到達しないことがあります。最初に読むべきなのは、アプリログではなく kubectl describe pod のState、Message、Eventsです。 エラーの概要 KubernetesのPod起動は、ざっくり次の段階に分けられます。 Scheduling ↓ Image pull ↓ Pod sandbox 作成 ↓ Container 作成 ↓ Container 起動 ↓ Application 実行 RunContainerError は、このうち Container作成または起動 の近辺で止まっている状態です。kubeletの実装では、RunContainerError はコンテナ起動時の失敗を表すエラーとして定義されています(sync_result.go)。 したがって、RunContainerError を見た時点で、少なくとも次の切り分けが必要です。 kubectl get pod <Pod名> -n <名前空間> \ -o jsonpath='{range .status.containerStatuses[*]}{.name}{"\t"}{.state.waiting.reason}{"\t"}{.state.waiting.message}{"\n"}{end}' initコンテナで止まっている場合は、見る場所が変わります。 ...

2026年8月5日 · ErrorLog

ContainerCreating:原因と解決策

冒頭まとめ ContainerCreating は、根本原因を示すエラー名ではありません。kubectl get pods が、Kubernetesでコンテナをまだ開始できていない状態を要約して表示したものです。 NAME READY STATUS RESTARTS AGE app-7f6f8d9c75-2kq8m 0/1 ContainerCreating 0 8m API上では、Podの段階は Pending、コンテナの状態は Waiting、その理由が ContainerCreating になっていることがあります。 Status: Pending State: Waiting Reason: ContainerCreating Kubernetes公式のPodライフサイクルは、kubectl の STATUS 欄をPodの phase と混同しないよう明記しています。ContainerCreating を見ただけでは、ボリューム、イメージ取得、Podの通信環境、コンテナ実行基盤のどこで止まったかは決まりません。 そこで、次に kubectl describe pod の Events を読みます。 Warning FailedMount 2m (x8 over 7m) kubelet MountVolume.SetUp failed for volume "config" : configmap "app-config" not found この場合、ContainerCreating は現在の待機状態、FailedMount はボリュームの準備に失敗した試行の記録です。直す対象を示しているのは、FailedMount より後ろの文です。 configmap "app-config" not found rpc error: code = ... desc = ... driver name ... not found in the list of registered CSI drivers mount failed: exit status 32 volume is already exclusively attached to one node つまり、ContainerCreating を直接直すのではなく、最新イベントの具体的な失敗を直します。FailedMount があるなら、最初に対象ボリューム名をPodの volumes と対応させ、参照先がSecret、ConfigMap、PVC、CSIのどれかを確定します。 ...

2026年8月5日 · ErrorLog

Liveness probe失敗:原因と解決策

冒頭まとめ Liveness probe failed は、kubeletが対象コンテナの生存確認に失敗した記録です。 Warning Unhealthy kubelet Liveness probe failed: Get "http://10.244.1.17:8080/healthz": dial tcp 10.244.1.17:8080: connect: connection refused 失敗が failureThreshold の回数だけ連続すると、kubeletは失敗したコンテナを終了させます。その後の再起動は restartPolicy に従います。Pod lifecycleの公式資料では、Pod単位の値は Always、OnFailure、Never で、既定値は Always と定義されています。そのため、Deploymentなど一般的なPodでは同じPod内でコンテナが再起動します。 Liveness probeが失敗 ↓ failureThreshold回連続 kubeletが対象コンテナを終了 ↓ restartPolicyがAlwaysまたはOnFailure 同じPod、同じNodeでコンテナを再起動 ↓ 失敗が続けば再起動待ちが長くなり、CrashLoopBackOffになり得る ここで、Podが削除されて新しいPodへ置き換わるわけではありません。Pod名とUIDは同じまま、コンテナの restartCount が増えます。複数コンテナのPodなら、probeに失敗したコンテナが対象です。 Kubernetes公式のprobe資料は、liveness probeを、停止しているように見えないまま処理が進まなくなったコンテナを再起動する仕組みとして説明しています。一時的な高負荷、外部データベースの停止、起動の遅さを検出するためのものではありません。 同じ接続失敗でも、readiness probeとは結果が違います。 Liveness probe failed → 対象コンテナを終了し、再起動対象にする Readiness probe failed → コンテナは動かしたまま、PodをServiceの通常転送先から外す 一時的に要求を受けられないだけなら、readinessProbeでServiceから外します。起動に時間がかかるなら startupProbe で、livenessの開始を待たせます。再起動しなければ回復できない状態だけを livenessProbe で判定します。 最初に確認するのは再起動回数ではなく、イベント末尾の失敗理由です。 connect: connection refused → 指定したportで待ち受けていない context deadline exceeded / timeout → timeout内に応答できない HTTP probe failed with statuscode: 500 → endpointが失敗用statusを返した command timed out / exit code != 0 → exec probeのcommandが失敗した エラーの概要 probeは、kubeletがコンテナへ定期的に行う診断です。HTTP、TCP、exec、gRPCの4方式があります。 ...

2026年8月5日 · ErrorLog

Readiness probe失敗:原因と解決策

冒頭まとめ Readiness probe failed は、kubeletが「このコンテナは現在、利用者からの要求を受ける準備ができていない」と判定した記録です。 Warning Unhealthy kubelet Readiness probe failed: Get "http://10.244.1.18:8080/readyz": context deadline exceeded 失敗が failureThreshold の回数だけ連続すると、kubeletはコンテナを終了せず、Podの Ready conditionを False にします。該当Podを選択するServiceでは、EndpointSliceの通常転送対象から外れます。 Readiness probeが失敗 ↓ failureThreshold回連続 コンテナはRunningのまま ↓ Container Ready=False ↓ Pod Ready=False ↓ 該当Serviceの通常転送先から外れる ↓ probeが再び成功 同じPodがReady=Trueへ戻り、転送先へ復帰する したがって、readiness失敗だけでは RESTARTS は増えません。kubectl get pod では次のように、STATUS は Running のまま、READY が 0/1 になることがあります。 NAME READY STATUS RESTARTS AGE app-0 0/1 Running 0 12m 同じprobe失敗でも、livenessProbeとは結果が反対です。 Readiness probe failed → 動かしたままServiceの通常転送先から外す Liveness probe failed → 対象コンテナを終了し、restartPolicyに従って再起動する ただし、readinessはPodのnetworkを切断する機能ではありません。Kubernetes公式のprobe資料が変更すると説明しているのは、PodのReady状態と、該当ServiceのEndpointSliceです。 ...

2026年8月5日 · ErrorLog

Terminating:原因と解決策

冒頭まとめ Terminating は、Podの phase ではありません。削除要求を受け、.metadata.deletionTimestamp が入ったPodを kubectl が一覧で示す表示です。 NAME READY STATUS RESTARTS AGE app-7d8f767544-pk4ch 1/1 Terminating 0 3d 削除要求がAPI Serverに受理されても、Podはすぐには消えません。Kubernetes公式のPod終了処理では、既定で30秒の猶予期間が設けられ、その間に preStop、終了シグナル、接続の退避、コンテナ停止などが進みます。finalizerがある場合は、そのfinalizerを管理するコントローラーの後処理が終わるまで、API上のオブジェクトも残ります。 したがって、数十秒の Terminating は異常とは限りません。長時間変わらない場合は、次の4つを分けて確認します。 猶予期間中の正常な終了処理なのか。 preStop またはアプリケーションの終了処理が完了しないのか。 finalizerを管理するコントローラーが後処理を完了できないのか。 配置先ノードまたはkubeletと通信できず、停止を確認できないのか。 ここで最も重要な事実訂正があります。 kubectl delete pod <Pod名> -n <名前空間> --grace-period=0 --force この強制削除は、ノード上のプロセスを確実に停止してからPodを消す操作ではありません。kubectl delete の公式リファレンスは、API Serverがkubeletによる終了確認を待たず、同じ識別情報を持つ処理が別のマシンで動き続け、データの不整合や損失につながる可能性を警告しています。 強制削除は一覧をきれいにする操作ではありません。古い処理が停止済み、または二度と共有資源へ接続できないと確認した後に限る、最後の手段です。 エラーの概要 Podを通常削除すると、API Serverはオブジェクトへ削除時刻と猶予期間を記録します。 metadata: deletionTimestamp: "2026-08-05T03:12:44Z" deletionGracePeriodSeconds: 30 この時点で削除要求は失敗していません。finalizerの公式説明によれば、finalizerを持つオブジェクトへの削除要求は 202 Accepted で受理され、.metadata.deletionTimestamp が設定されます。その後、必要な後処理が済み、finalizerの一覧が空になると削除が完了します。 Terminating は、この途中経過を kubectl が表示したものです。API上のPodの status.phase は、終了処理中も Running や Pending のままの場合があります。 kubectl get pod <Pod名> -n <名前空間> \ -o jsonpath='{.status.phase}{"\t"}{.metadata.deletionTimestamp}{"\t"}{.metadata.finalizers}{"\n"}' Running 2026-08-05T03:12:44Z [batch.kubernetes.io/job-tracking] もう1つ混同しやすいのが、次の3種類の時間です。 ...

2026年8月5日 · ErrorLog