Короткий ответ
Кроме явной нехватки CPU/памяти, нужно проверить: taints на узлах без соответствующих tolerations у Pod, несовместимые nodeAffinity/nodeSelector требования, превышение ResourceQuota в namespace, нехватку доступных IP-адресов в сети подов, и недоступность запрошенного PersistentVolume/StorageClass — всё это видно в kubectl describe pod в секции Events, но формулировки сообщений нужно уметь различать.
Как это работает подробнее
планировщик перебирает все узлы и отфильтровывает неподходящие по множеству предикатов (ресурсы, taints, affinity, топология); если ни один узел не прошёл фильтрацию, Pod остаётся Pending, а причина агрегируется в одном сообщении FailedScheduling, которое может скрывать сразу несколько факторов (например, "insufficient cpu" на одних узлах и "node(s) had taint" на других).
Пример кода
kubectl describe pod batch-job-9f8
Warning FailedScheduling default-scheduler 0/8 nodes are available:
5 Insufficient cpu, 3 node(s) had taint {dedicated: gpu} that the pod didn't tolerate.Что использовать на практике
- Практика. при сложном сообщении об ошибке стоит проверять по отдельности каждое условие:
kubectl get nodes -o json | jq '.items[].spec.taints'для taints,kubectl describe node <node>для текущей аллокации ресурсов,kubectl get resourcequota -n <namespace>для ограничений namespace. ResourceQuota — частая неочевидная причина: кластер в целом может иметь свободные ресурсы, но namespace уже исчерпал выделенную ему квоту.
Подводные камни
- Риски. сразу делать вывод "не хватает ресурсов кластера" и добавлять узлы, когда реальная причина — ResourceQuota namespace или taint, который просто забыли toleration'ить при переносе workload на новый пул узлов; не проверять топологические ограничения (
topologySpreadConstraints), которые тоже могут сделать Pod непланируемым при недостаточном числе доступных зон.