クイック解決策
トポロジ制約が原因でPodがPending状態で止まっている場合、通常は以下の2つの方法ですぐに実行状態にすることができます。
- ソフト制約に切り替える:
whenUnsatisfiable: DoNotScheduleをwhenUnsatisfiable: ScheduleAnywayに変更します。これにより、スケジューラーは可能な限り分散を試みますが、Podの実行を優先するようになります。 - 計算条件を緩める:
maxSkewの値を増やします。現在1の場合は2を試してください。これにより、ノードやゾーン間でのより不均等な配置が許容されるようになります。
# DeploymentのYAMLを更新:
whenUnsatisfiable: ScheduleAnyway # DoNotScheduleから変更
原因について
KubernetesがPodのスケジューリングに失敗しているのは、高可用性のために設定したルールが現在のクラスターの状態に対して厳しすぎるためです。これはスケジューラーが解けない数学的なパズルだと考えてください。主な原因には以下のようなものがあります。
- 「完璧なバランス」の罠:
maxSkew: 1を設定しているが、ノード数が不揃いな場合です。例えば、5つのPodを2つのノードにskew 1で分散させることは数学的に不可能です。 - ラベルの欠落:
topologyKey(topology.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です。これにより、スケジューラーが新しいパラメータの範囲内で動作していることが確認できます。

