Pending: почему под не запускается и что значит «0/3 nodes are available»
Команда KAI Lab · · 8 мин чтения
Статус Pending значит, что Kubernetes принял под, но ещё не запустил его контейнеры: чаще всего планировщик не нашёл подходящую ноду, реже под уже назначен на ноду и ждёт образ или том. Главные причины — на нодах не хватает CPU или памяти под requests, ноды закрыты taints, не совпадают nodeSelector или affinity, PersistentVolumeClaim не привязан к тому.
Pending сам не проходит. В документации Kubernetes на примере пода с неподъёмным запросом памяти так и сказано: он будет висеть в Pending бесконечно. Хорошая новость: планировщик всегда объясняет, почему не может разместить под, и это объяснение надо только прочитать.
Что значит Pending
Pending — одна из пяти фаз пода. По документации, это время, пока под ждёт планирования, и время, пока скачиваются образы. Поэтому первый вопрос — назначен ли под на ноду:
$ kubectl get pods -n shop -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
search-7b6d5f8c9-p4n2x 0/1 Pending 0 14m <none> <none> <none> <none>NODE <none> — планировщик под не разместил, дальше читайте эту статью. Если нода есть, а в STATUS стоит ContainerCreating, ErrImagePull или CreateContainerConfigError, фаза пода по-прежнему Pending, но проблема уже на ноде: образ, тома или конфигурация. Для них есть отдельные разборы: ImagePullBackOff и CreateContainerConfigError.
Все такие поды в кластере показывает одна команда:
$ kubectl get pods -A --field-selector=status.phase=PendingГлавный инструмент: событие FailedScheduling
$ kubectl describe pod search-7b6d5f8c9-p4n2x -n shop
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 2m15s (x4 over 14m) default-scheduler 0/4 nodes are available: 1 node(s) had untolerated taint(s), 3 Insufficient memory. preemption: 0/4 nodes are available: 1 Preemption is not helpful for scheduling, 3 No preemption victims found for incoming pod.Сообщение читается так: всего в кластере 4 ноды, ни одна не подошла. Одну отсекла метка-запрет (taint), на трёх не хватает памяти. Часть после preemption: объясняет, почему не помогло вытеснение подов с меньшим приоритетом: на ноде с taint это ничего не изменит, а на остальных нет подходящих жертв.
Типичные фрагменты этого сообщения и их смысл — в таблице ниже. Одна нода может попасть сразу под несколько причин. До Kubernetes 1.34 сообщение про taint включало его ключ, например node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, в новых версиях ключа нет, и его надо смотреть на самих нодах.
Причины Pending: таблица
| Причина | Что в FailedScheduling | Как исправить |
|---|---|---|
| Не хватает CPU или памяти под requests | Insufficient cpu, Insufficient memory | снизить requests до реальных, освободить место, добавить ноды |
| Taint без toleration | node(s) had untolerated taint(s) | toleration в поде или снять taint с ноды |
| Не совпадают метки | node(s) didn't match Pod's node affinity/selector | поставить метку на ноду или поправить селектор |
| PVC не привязан | pod has unbound immediate PersistentVolumeClaims | исправить StorageClass, проверить provisioner, создать PV |
| Том в другой зоне или на другой ноде | node(s) didn't match PersistentVolume's node affinity | ноды в зоне тома или том в нужной зоне |
| Занят hostPort | node(s) didn't have free ports for the requested pod ports | убрать hostPort, открыть сервис через Service |
| Ноды выведены из планирования | node(s) were unschedulable | kubectl uncordon, если обслуживание закончено |
Не хватает ресурсов
Планировщик смотрит на requests, а не на реальное потребление. Документация Kubernetes подчёркивает: даже если нода почти простаивает, под не попадёт на неё, когда сумма requests не помещается в доступные ресурсы. Сколько уже занято, показывает kubectl describe node:
$ kubectl describe node worker-2
...
Allocatable:
cpu: 3920m
memory: 7862592Ki
pods: 110
...
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 3450m (88%) 6 (153%)
memory 7012Mi (91%) 9Gi (120%)Allocatable меньше физической памяти ноды: часть резервируется под систему и kubelet. Если поду нужен 1Gi, а свободно около 660Mi по requests, он сюда не влезет, сколько бы ни показывал kubectl top.
Что делать:
- сравнить requests пода с реальным потреблением и снизить их, если они завышены;
- проверить, что под вообще помещается хоть на одну ноду: запрос
cpu: 1.1на нодах с 1 CPU не разместится никогда; - убрать ненужные поды или добавить ноды. Если в кластере работает Cluster Autoscaler, в событиях пода появятся
TriggeredScaleUpилиNotTriggerScaleUpс объяснением, почему новая нода не поможет; - для важных сервисов задать PriorityClass: под с высоким приоритетом может вытеснить менее важные.
Если в пространстве имён исчерпана ResourceQuota, под не появится вовсе. Тогда ищите событие FailedCreate с текстом exceeded quota у ReplicaSet, а не у пода.
Taints без tolerations
Taint — метка-запрет на ноде: поды без подходящего toleration туда не планируются. Посмотреть их можно так:
$ kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints[*].key
NAME TAINTS
cp-1 node-role.kubernetes.io/control-plane
worker-1 dedicated
worker-2 <none>
worker-3 node.kubernetes.io/disk-pressureТри типичных источника:
- Управляющие ноды. kubeadm ставит на них
node-role.kubernetes.io/control-plane:NoSchedule, и обычные поды туда не попадают. Так и задумано. - Выделенные ноды. Например,
dedicated=gpu:NoScheduleдля нод с видеокартами. Нужен toleration в поде. - Состояние ноды. Kubernetes сам ставит taints
node.kubernetes.io/disk-pressure,memory-pressure,not-ready,unreachable. Если ноды под давлением диска, лечить нужно диск: см. статьи под Evicted и no space left on device в Docker.
Toleration в манифесте пода по образцу из документации:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"Снять лишний taint с ноды — та же команда с минусом в конце: kubectl taint nodes worker-1 dedicated=gpu:NoSchedule-. Учтите, что toleration только разрешает попасть на ноду, но не притягивает к ней. Чтобы под шёл именно на выделенные ноды, к toleration добавляют nodeSelector или affinity.
nodeSelector и affinity
Если под требует ноды с меткой, которой нет ни у одной ноды, планировщик ответит node(s) didn't match Pod's node affinity/selector. Проверка в две команды:
$ kubectl get pod search-7b6d5f8c9-p4n2x -n shop -o jsonpath='{.spec.nodeSelector}'
{"disktype":"ssd"}
$ kubectl get nodes -l disktype=ssd
No resources foundРешение — поставить метку нужной ноде (kubectl label nodes worker-3 disktype=ssd) или поправить селектор. Для requiredDuringSchedulingIgnoredDuringExecution правило жёсткое, как у nodeSelector. Если допустимо запускаться и на других нодах, используйте preferredDuringSchedulingIgnoredDuringExecution.
Метки меняются и при обновлениях. 14 марта 2023 года Reddit был недоступен 314 минут: при обновлении кластера до Kubernetes 1.24 kubeadm снял с управляющих узлов метку node-role.kubernetes.io/master, а по ней Calico выбирал узлы для маршрутизации между подами. Подробности — в разборе сбоя Reddit. Вывод для Pending тот же: перед обновлением ищите все селекторы по меткам, которые могут исчезнуть.
PersistentVolumeClaim не привязан
Под с томом не запланируют, пока его PVC не связан с PersistentVolume, если у StorageClass режим привязки Immediate. Смотрите на сам PVC:
$ kubectl get pvc -n shop
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
data-search-0 Pending premium-rwo <unset> 14m
$ kubectl describe pvc data-search-0 -n shop
...
Warning ProvisioningFailed 12s (x58 over 14m) persistentvolume-controller storageclass.storage.k8s.io "premium-rwo" not foundЧто бывает в событиях PVC:
storageclass.storage.k8s.io "…" not found— опечатка вstorageClassNameили класс не создан. Список классов —kubectl get storageclass, класс по умолчанию помечен(default).no persistent volumes available for this claim and no storage class is set— динамического создания томов нет, а подходящего PV никто не завёл.Waiting for a volume to be created either by the external provisioner …— ждём CSI-драйвер. Если это надолго, проверьте, что его поды работают.waiting for first consumer to be created before binding— это нормально для режимаWaitForFirstConsumer: том создадут, когда планировщик выберет ноду.
Если PVC привязан, но в FailedScheduling node(s) didn't match PersistentVolume's node affinity, том создан в другой зоне доступности или это локальный том другой ноды. Под может жить только там, где доступен его диск.
Частые вопросы
Сколько под может висеть в Pending? Сколько угодно. Под не перейдёт в ошибку сам: планировщик будет повторять попытки, когда в кластере что-то меняется, например добавилась нода или освободились ресурсы. Pending дольше пары минут — повод читать события.
Почему Insufficient memory, если kubectl top показывает свободную память? Планировщик считает requests, а не фактическое потребление. Если соседние поды запросили память с запасом и не используют её, для планировщика она всё равно занята. Сравните Allocated resources в kubectl describe node с реальным потреблением и снизьте завышенные requests.
Что значит «Preemption is not helpful for scheduling»? Планировщик проверил, поможет ли вытеснить поды с меньшим приоритетом, и понял, что нет. Обычно причина не в ресурсах: taint, несовпадающие метки или том в другой зоне. Вытеснение освобождает CPU и память, но не снимает taint.
Под в ContainerCreating — это тоже Pending? Да, фаза та же, но под уже на ноде. Планирование прошло, и проблема в запуске: образ скачивается или не скачивается, том не подключился, нет Secret. Смотрите события FailedMount, Failed и статус контейнера.
Как быстро проверить весь кластер на такие проблемы? kubectl get pods -A --field-selector=status.phase=Pending покажет все поды в фазе Pending, а kubectl get events -A --field-selector reason=FailedScheduling — объяснения планировщика. Разобрать такое сообщение вслух часто просят на собеседовании по Kubernetes.
Потренироваться на практике
В симуляторе DevOps KAI Lab в месяце про Kubernetes есть тикет «Под висит в Pending»: разработчик уверен, что места в кластере полно, а под не запускается. Консоль в браузере отдаёт реальные выводы kubectl, и причину нужно найти самому. Проверить себя можно в бесплатном тесте навыков DevOps.
Источники
- Kubernetes. Pod Lifecycle — фаза Pending.
- Kubernetes. Debug Pods и Debug Running Pods — под в Pending, события планировщика,
kubectl get events. - Kubernetes. Resource Management for Pods and Containers — планирование по requests, FailedScheduling,
kubectl describe nodes. - Kubernetes. Assign Memory Resources to Containers and Pods — под с большим запросом висит в Pending бесконечно.
- Kubernetes. Taints and Tolerations —
kubectl taint, tolerations, taints по состоянию ноды. - Kubernetes. Assigning Pods to Nodes — nodeSelector и affinity.
- Kubernetes. Well-Known Labels, Annotations and Taints — taint
node-role.kubernetes.io/control-plane. - Kubernetes. Persistent Volumes и Storage Classes — привязка PVC,
WaitForFirstConsumer. - Kubernetes, исходный код планировщика: формат FitError и плагин TaintToleration — тексты причин, изменение сообщения про taint в 1.34.
- Reddit Engineering. You Broke Reddit: The Pi-Day Outage, 21.03.2023; Kubernetes. kubeadm: PR #107533 — снятие метки
masterв 1.24.