Kubernetes: Pod が Running / Ready にならないときの切り分け手順
kubectl get pod の STATUS 列だけ見て原因を決めると外しやすい。-o yaml(Conditions とコンテナの終了状態)→ describe(Events)→ logs の順に見て、どの段階で止まっているかを先に決める。
まず知っておくこと
- STATUS 列と
status.phaseは別物。CrashLoopBackOff と表示されていても、再起動対象のコンテナが残っていれば phase はRunningのままbashkubectl get pod crashloop -o jsonpath='{.status.phase}' # → Running - 健全かどうかは READY 列・RESTARTS 列・Conditions(
PodScheduled→PodReadyToStartContainers→Initialized→ContainersReady→Ready)で見る。どこで False になっているかで段階がわかる
手順
kubectl get pod <pod> -o yamlでstatus.conditionsとcontainerStatusesのstate/lastState(終了コード・reason)を見るkubectl describe pod <pod>の Events で Reason を見る- 起動しているなら
kubectl logs <pod> -c <container> --tail=100、落ちているなら--previousで直前の実行のログを見る - ノード側が怪しければ
kubectl describe node <node>でMemoryPressure/DiskPressure/PIDPressureと、Requests / Limits の集計を見る(集計は実使用量ではない)
Event Reason から当たりをつける
| Reason | よくある原因 |
|---|---|
FailedScheduling | リソース不足、Affinity / Taint 不一致、PVC が未バインド |
Failed(ErrImagePull)→ BackOff(ImagePullBackOff) | 後者は「再試行待ち」の表示。原因は直前の失敗メッセージにある |
Failed(CreateContainerConfigError) | 存在しない ConfigMap / Secret のキーを参照している |
BackOff(CrashLoopBackOff) | アプリが終了を繰り返している。--previous のログと終了コードを見る |
Unhealthy | Probe の失敗(設定ミスか、アプリの実装か) |
FailedCreatePodSandBox | ランタイムや CNI の失敗 |
FailedMount / FailedAttachVolume | ボリューム |
イメージ取得の失敗メッセージは、文言で次の確認先が決まる。
| メッセージ | 確認するもの |
|---|---|
| not found | 名前・タグ・push 状況・権限 |
| no such host | レジストリ名、ノードの DNS |
| timeout / connection refused | Proxy・Firewall・ノードからの到達性 |
| unauthorized / 401 / 403 | imagePullSecrets、Secret の namespace |
| x509 | 証明書の期限・CA・ノードの信頼設定 |
| 429 / 5xx | レート制限、ミラーや Proxy |
起動直後に落ちるときは、exec format error(イメージとノードの CPU アーキテクチャ違い)、permission denied(実行権限・実行ユーザー)、read-only file system(readOnlyRootFilesystem)も典型。
Probe の考え方
- Readiness が失敗しても再起動はしない。Service の転送先(EndpointSlice)から外れるだけ。
kubectl get endpointslices -l kubernetes.io/service-name=<svc> -o yamlで確認する - Liveness / Startup の連続失敗は、コンテナの停止と再起動につながる。起動が遅いアプリは Startup Probe を付けるか、
timeoutSeconds・periodSeconds・failureThresholdを合わせる - Probe の path が正しいかは
kubectl port-forward pod/<pod> 8080:80してから同じ path を叩いて確かめる - DB や外部 API まで見る「deep health check」を Liveness に入れない。共有 DB の一時障害で全 Pod が一斉に再起動し、再接続の集中で復旧がさらに遅れる。Readiness に入れても全 Pod が転送先から外れる。依存先の障害はアプリ側で扱い、DB が要るリクエストだけ 503(必要なら
Retry-After)を返す設計も検討する
その他の小技
- ConfigMap / Secret を環境変数で渡している場合、更新しても既存 Pod には反映されない。
kubectl exec <pod> -- printenv KEYで確認し、kubectl rollout restart deployment/<name>で作り直す - ServiceAccount の権限不足は
kubectl rolesum <sa> -n <ns>(kubectl-rolesum プラグイン)で、持っている権限を一覧できる - ログだけで原因がわからなければ、同じイメージと入力で
docker runしてローカルで再現するか試す。再現しなければ環境差(環境変数・リソース制限・ネットワーク)を疑う
関連
- Kubernetes の「メモリ使用量」は一つではない: OOMKilled と Eviction の見分け方
- Kubernetes の Disk Pressure Eviction: どの領域が埋まり、何が回収され、どの Pod が退避されるか
- stern: 複数 Pod のログをまとめて tail し、--include / --exclude で行を絞る
- k9s の次の候補: sofka / k10s / Radar — kubeconfig だけで使える Kubernetes TUI・UI