Pod が Pending で止まるとき — 原因 7 つと確認の順序

読了 5分

デプロイしたのに Pod が Pending から動きません。Pending はエラーではなく「実行するノードがまだ決まっていない」状態なので、ログもなく(コンテナが起動前なので kubectl logs は空振りです)、原因がすぐには見えません。この記事は Pending の原因を実務の頻度順に 7 つ整理します。試験観点のトラブルシューティング全般は CKA #22 で扱ったので、ここでは運用中に遭遇するシナリオに集中します。

確認は一か所から始めます — Events #

Pending の理由は、ほぼ常にスケジューラが Events に書き残しています。

kubectl describe pod
$ kubectl describe pod api-server-7d4b9c-x2k8p
...
Events:
  Type     Reason            Message
  ----     ------            -------
  Warning  FailedScheduling  0/6 nodes are available: 3 Insufficient cpu,
                             2 node(s) had untolerated taint {gpu: "true"},
                             1 node(s) didn't match Pod's node affinity/selector.

このメッセージが診断のほぼすべてです。「ノード 6 台中 0 台が利用可能」とその内訳(CPU 不足 3 台、taint 2 台、affinity 不一致 1 台)が出るので、以下の原因リストはこのメッセージを解釈する辞書だと思ってください。

1. リソース不足 — Insufficient cpu/memory #

最も多い原因です。スケジューラはノードの実使用量ではなく requests の合計で空きを計算します。Insufficient cpu は「すべてのノードで、残りの割り当て可能量(allocatable)よりこの Pod の requests が大きい」という意味です。

  • 確認: kubectl describe node のノードごとの Allocated resources で、requests の合計がどれだけ埋まっているかを見ます。
  • 対処: まずはノードの増設か他のワークロードの整理を検討します。ただしその前に、次の項目(過大な requests)を先に疑う価値があります。

2. 過大な requests — 実使用は低いのに予約が満杯 #

kubectl top node の実使用率は 30% なのに Insufficient cpu が出るなら、誰かの requests が実際より大きく設定されています。requests は予約なので、使わなくても枠を占有します。「とりあえず大きめ」の requests が積もると、クラスタの半分が空の予約でロックされます。

  • 確認: ワークロードごとの requests と実使用を並べて見ます(metrics-server、または VPA の推奨モード)。
  • 対処: 実測に基づいて requests を再調整します。基準の決め方は K8s 中級 #4 の概念の上で、別の記事として扱います。

3. nodeSelector・affinity の不一致 #

didn't match Pod's node affinity/selector が見えたら、Pod が要求するラベルを持つノードがないか足りないケースです。ノードのラベルが変更・削除されたか、マニフェストのラベルの打ち間違い(disktype: ssd vs diskType: ssd)が典型です。

  • 確認: kubectl get nodes --show-labels で実際のラベルとマニフェストの要求を突き合わせます。
  • 対処: ラベルを合わせるか、必須でない制約なら required を preferred affinity に緩めます。

4. taint を許容する toleration がない #

untolerated taint は、ノード側が「誰でも来るな」と宣言しているケースです。GPU ノード、専用ノードプール、そしてコントロールプレーンノードのデフォルトの taint が該当します。クラスタに GPU ノードしか空きが残っていないと、一般の Pod が全部 Pending になる、という事故が起きます。

  • 確認: kubectl describe node <node> | grep Taints で見ます。
  • 対処: 意図した専用ノードなら一般ワークロード用のノードを確保し、そのノードに行くべき Pod なら toleration を追加します。

5. PVC がバインドされない #

ボリュームを使う Pod は、PVC が準備できて初めてスケジュールされます。waiting for a volume to be created や、PVC が Pending ならこちらです。StorageClass 名の打ち間違い、プロビジョナーの未インストール、そして WaitForFirstConsumer モードで他の制約と絡んでノードが決められないケースがよくあります。AZ のあるクラウドでは「ボリュームは a ゾーンにあるのに、スケジュール可能なノードは b ゾーンだけ」というゾーンの不一致も常連です。

  • 確認: kubectl get pvckubectl describe pvc の Events を見ます。
  • 対処: StorageClass の確認と、ゾーン分散の見直し(ボリュームを使うワークロードの affinity はゾーンと一緒に設計)です。

6. ResourceQuota・LimitRange 違反 #

ネームスペースにクォータが掛かっていると、ノードに空きがあっても拒否されます。この場合 Pod が作成すらされないか(ReplicaSet の Events に記録)、exceeded quota のメッセージが残ります。新しいチームのオンボーディングでデフォルトのクォータをコピーして使っていて引っかかるパターンが多いのです。

  • 確認: kubectl describe quota -n <ns> と ReplicaSet・Deployment の Events を見ます。
  • 対処: クォータの調整か、ワークロードの requests の縮小です。

7. Cluster Autoscaler が増えないケース #

「オートスケーラーがあるからノードは自動で増えるはず」が裏切られるケースです。ノードグループの上限到達、クラウド側のインスタンス上限・容量不足(特定タイプの品切れ)、そして Pod 自身の制約(affinity・taint)のせいで、増やしてもどうせ行けないノードだから増やさないという場合があります。Autoscaler は理由をイベントとログに残します。

  • 確認: kubectl describe podNotTriggerScaleUp イベントと autoscaler のログを見ます。
  • 対処: ノードグループ上限の引き上げ、インスタンスタイプの多様化、Pod の制約の緩和です。

診断手順のまとめ #

  1. kubectl describe pod — まず Events を読みます。FailedScheduling のメッセージが原因の分布を教えてくれます。
  2. Insufficient なら describe node の Allocated resources で予約の飽和を確認し、実使用と突き合わせて過大な requests を探します。
  3. selector/taint ならノードのラベル・taint とマニフェストを突き合わせます。
  4. ボリュームのワークロードなら PVC の状態とゾーン配置を見ます。
  5. クォータのメッセージならネームスペースのクォータを、オートスケーラー環境なら NotTriggerScaleUp イベントを確認します。

まとめ #

  • Pending はエラーではなく「行くノードがない」状態で、理由はほぼ常に describe の FailedScheduling イベントに書いてあります。
  • スケジューラは実使用ではなく requests の合計で計算します。実使用が低いのに空きがないなら、まず過大な requests を疑います。
  • ラベル・taint の不一致は、マニフェストとノードの状態の突き合わせですぐ捕まります。
  • ボリュームの Pod は PVC とゾーン配置まで、オートスケーラー環境は「なぜ増やさなかったか」のイベントまで確認すれば十分です。
  • 同じメッセージが繰り返されるなら、個別の対処より requests の算定基準とノードプールの設計を直すほうが根本的な対策です。
X