Kubernetesエラーの解決方法: 0/3 nodes are available: pod topology spread constraints

intermediate☸️ Kubernetes2026-07-23| DeploymentまたはPodのスペックでTopologySpreadConstraintsを使用している、Kubernetes 1.19以降のクラスター(EKS, GKE, AKS、またはセルフマネージド)。

Error Message

0/3 nodes are available: 3 node(s) didn't match pod topology spread constraints.
#kubernetes#k8sトラブルシューティング#devops#スケジューリング

クイック解決策

トポロジ制約が原因でPodがPending状態で止まっている場合、通常は以下の2つの方法ですぐに実行状態にすることができます。

  • ソフト制約に切り替える: whenUnsatisfiable: DoNotSchedulewhenUnsatisfiable: ScheduleAnyway に変更します。これにより、スケジューラーは可能な限り分散を試みますが、Podの実行を優先するようになります。
  • 計算条件を緩める: maxSkew の値を増やします。現在 1 の場合は 2 を試してください。これにより、ノードやゾーン間でのより不均等な配置が許容されるようになります。
# DeploymentのYAMLを更新:
whenUnsatisfiable: ScheduleAnyway # DoNotScheduleから変更

原因について

KubernetesがPodのスケジューリングに失敗しているのは、高可用性のために設定したルールが現在のクラスターの状態に対して厳しすぎるためです。これはスケジューラーが解けない数学的なパズルだと考えてください。主な原因には以下のようなものがあります。

  • 「完璧なバランス」の罠: maxSkew: 1 を設定しているが、ノード数が不揃いな場合です。例えば、5つのPodを2つのノードにskew 1で分散させることは数学的に不可能です。
  • ラベルの欠落: topologyKeytopology.kubernetes.io/zone など)がノードに存在しません。スケジューラーがラベルを見つけられない場合、そのノードは不適格であると判断されます。
  • リソースの断片化: 十分なノードがあっても、分散条件を満たすためにPodを配置すべき特定のノードがすでに満杯であるか、テイント(taint)が付与されている場合があります。
  • ラベルの重複: labelSelector が広すぎます。2つの異なるDeploymentが app: web ラベルを共有している場合、Kubernetesは分散を計算する際にそれらすべてのPodを合算してカウントします。

ステップバイステップの解決策

1. ノードラベルの確認

適切なラベルがないと、スケジューラーは判断ができません。Podをゾーン間で分散させている場合は、ノードが実際にどのゾーンに属しているかを報告しているか確認してください。

kubectl get nodes --show-labels

YAMLで定義したキーを確認します。topology.kubernetes.io/zone を使用しているのに、ノードに kubernetes.io/hostname しかない場合、制約は毎回失敗します。YAMLを実際のノードラベルに合わせてください。

2. ソフト制約への移行

DoNotSchedule はハードな要件です。大規模な本番環境には適していますが、メンテナンスやスケーリング時には小規模なクラスターを不安定にする可能性があります。これを ScheduleAnyway に変更することで、理想的な分散状態に反する場合でもPodをノードに配置できるようになります。

topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: ScheduleAnyway
    labelSelector:
      matchLabels:
        app: my-app

3. maxSkewの再計算

maxSkew 値は、任意の2つのトポロジドメイン間でのPod数の最大許容差を定義します。3ノードのクラスターでは、maxSkew: 1 は3、4、または5つのPodに対して完璧に機能します。しかし、1つのノードがダウンすると、同じ maxSkew: 1 が原因で、残りの2つのノードに4つ目のPodをスケジュールできなくなる可能性があります。値を 2 に増やすことで、障害時にも余裕を持たせることができます。

4. ラベルセレクターの分離

制約内の labelSelector が厳密であることを確認してください。汎用的すぎると、スケジューラーは計算に関係のないPodを含めてしまいます。特定のバージョンやコンポーネントのラベルを使用して、計算が特定のDeploymentのPodにのみ適用されるようにします。

# 他のアプリをカウントしないようにユニークなラベルを使用する
labelSelector:
  matchLabels:
    app: billing-api
    tier: backend

修正の確認方法

変更を適用した後、Podが正しく移動し分散されているかを確認する必要があります。

Podステータスの監視

kubectl get pods -w

Podが Pending から Running に遷移するはずです。Pending のままの場合は、kubectl describe pod <pod-name> を実行して、Insufficient CPU などの新しいエラーが発生していないか確認してください。

分散状況の分析

各ノードに具体的に何個のPodが配置されたかを確認するには、次のコマンドを実行します。

kubectl get pods -l app=my-app -o custom-columns=NODE:.spec.nodeName | sort | uniq -c

3 node-a および 2 node-b のような出力が表示されれば、skewは1です。これにより、スケジューラーが新しいパラメータの範囲内で動作していることが確認できます。

Related Error Notes