何が起きているか
PodがしばらくPending状態のままになっています。kubectl describeで確認すると、次のような出力が表示されます:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 30s default-scheduler 0/3 nodes are available: 3 Insufficient cpu.
Kubernetesのスケジューラーは3つのノードすべてを確認しましたが、どのノードもPodのリクエストを満たすだけの空きCPUがありませんでした。そのためスケジューラーは断念し、Podは待機状態のままとなっています。
これはCrashLoopBackOff(Podは起動するがクラッシュする)やImagePullBackOff(イメージをプルできない)とは異なります。この場合、Podはそもそも起動せず、コンテナが実行される前のスケジューリング段階で止まっています。
再現と診断
ステップ1: エラーを確認する
kubectl describe pod <pod-name> -n <namespace>
一番下のEventsセクションまでスクロールすると、FailedSchedulingの警告が表示されます:
0/3 nodes are available: 3 Insufficient cpu.
ステップ2: PodのCPUリクエストを確認する
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[*].resources}'
またはDeploymentのYAMLを直接確認します:
resources:
requests:
cpu: "2000m" # ← スケジューラーがノードを探す際に使用する値
limits:
cpu: "4000m"
スケジューラーはノードへの配置を決定する際に、limitsではなくrequestsを使用します。2000mのリクエストは各ノードに2コア分の空きが必要であることを意味し、これは非常に大きな要求です。
ステップ3: ノードの実際の容量と割り当て可能なCPUを確認する
kubectl describe nodes | grep -A 5 'Allocatable\|Allocated resources'
よりすっきりした表示で確認するには:
kubectl get nodes -o custom-columns=NAME:.metadata.name,CPU:.status.allocatable.cpu,MEMORY:.status.allocatable.memory
次に、各ノードの詳細を確認してすでに割り当てられているリソースを把握します:
kubectl describe node <node-name> | grep -A 10 'Allocated resources'
出力例:
Allocated resources:
(Total limits may be over 100 percent, i.e., no guarantee)
Resource Requests Limits
-------- -------- ------
cpu 1850m (92%) 3200m (160%)
memory 1Gi (55%) 2Gi (110%)
92%が割り当て済みの場合、200mを要求する新しいPodでも配置できません。空きスペースがないのです。
解決方法
オプション1: PodのCPUリクエストを削減する(手軽な修正)
ほとんどの場合、リクエストが高く設定されすぎています。アプリが起動時に実際に使用する量に合わせた現実的な値に下げましょう。
resources:
requests:
cpu: "100m" # 2000mから削減
memory: "256Mi"
limits:
cpu: "1000m"
memory: "512Mi"
よくある間違いとして、アプリのピーク時が200mなのにrequests.cpu: "2"(2コア)を設定してしまうことがあります。limitは高いままで問題ありません。requestsは最悪ケースや理想値ではなく、通常の使用量の正直な見積もりにする必要があります。
変更を適用します:
kubectl apply -f your-deployment.yaml
オプション2: クラスターをスケールアップする(ノードを追加する)
リクエストが正しく設定されていて、単純に容量が不足している場合もあります。ノードを追加するのが直接的な解決策です。
GKE:
gcloud container clusters resize <cluster-name> \
--node-pool <pool-name> \
--num-nodes 5 \
--region <region>
EKS(マネージドノードグループ):
aws eks update-nodegroup-config \
--cluster-name <cluster-name> \
--nodegroup-name <nodegroup-name> \
--scaling-config minSize=2,maxSize=10,desiredSize=5
オンプレミス: 新しいVMをプロビジョニングし、kubeadm joinでクラスターに参加させます。
オプション3: Cluster Autoscalerを有効にする
クラウドユーザーにはよりスマートな選択肢があります: Cluster Autoscalerです。スケジューラーがPodを配置できない場合に自動的に新しいノードをプロビジョニングするため、手動での対応が不要になります。
# オートスケーラーがすでに実行中か確認
kubectl get pods -n kube-system | grep cluster-autoscaler
インストールされていない場合は、デプロイします(Workload Identityを使用したGKEの例):
kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/gce/examples/cluster-autoscaler-autodiscover.yaml
次に、ノードグループにアノテーションを付けて、オートスケーラーがスケール対象として認識できるようにします。
オプション4: 他のワークロードを退避またはスケールダウンする
クラスター全体でCPUを消費しているものを調べます:
kubectl top nodes
kubectl top pods --all-namespaces --sort-by=cpu | head -20
アイドル状態または過剰にレプリカが設定されたDeploymentが原因であることが多いです。スケールダウンしてスペースを確保します:
kubectl scale deployment <other-deployment> --replicas=1 -n <namespace>
オプション5: 大きなデフォルト値を設定するLimitRangeを確認する
resourcesブロックのないPodはKubernetesからゼロのリクエストを受け取り、それだけではこのエラーは発生しません。しかし、ネームスペース内のLimitRangeが自動的に大きなデフォルト値を注入する場合があります。
kubectl get limitrange -n <namespace>
kubectl describe limitrange <name> -n <namespace>
LimitRangeが注入する値を上書きするために、PodのSpecに明示的なrequestsを設定します。
修正の確認
変更を適用したら、Podをリアルタイムで監視します:
kubectl get pods -n <namespace> -w
通常1〜2分以内に、Pending → ContainerCreating → Runningと変化するはずです。
スケジューリングの失敗がないことを確認します:
kubectl describe pod <pod-name> -n <namespace> | grep -A 10 Events
FailedSchedulingイベントがなければ完了です。
教訓
- 最悪ケースではなく、現実的なrequestsを設定する。 スケジューラーは
requestsに基づいて実際の配置を決定します。200mしか使用しないのに4コアをリクエストすると、クラスター内のすべてのノードで予約容量が無駄になります。 - RequestsとLimitsは異なる役割を持つ。
requests= スケジューラーが配置時に予約するリソース量。limits= 実行時に強制される上限値。requestsは低く現実的に保ち、limitsは実際に許容できる最大値に設定します。 kubectl top nodesは使用量を表示するが、割り当て量ではない。 ノードのCPU使用量が30%でも、CPUリクエストが95%に達している場合があります。スケジューラーはリアルタイムの使用量ではなくrequestsに基づいて動作します。常にkubectl describe nodeで確認し、Allocated resourcesセクションの数値を見てください。それが重要な数値です。- Cluster Autoscalerはすぐにその価値を発揮する。 クラウドインフラを使用していてこのエラーに複数回遭遇した場合、オートスケーラーを導入すれば手動でのボトルネックを完全に解消できます。必要になる前に設定しておきましょう。

