Задача 19. Нода под давлением: кого вытеснят первым

На ноде кончается место на диске, и поды начинают выселяться — включая те, что ничего не писали. Разбираем пороги kubelet, разницу между вытеснением и OOMKill и почему логи в файл опасны.
Опубликовано:

Задача

На ноде заканчивается место на диске. Kubelet начинает выселять поды со статусом Evicted. Среди выселенных — поды, которые вообще ничего не пишут на диск.

Вопрос: почему выселяют «невиновных» и по какому принципу выбирается жертва?

Что кажется очевидным

«Должны выселять того, кто занял диск». Логично, но kubelet устроен иначе — и понимание этого меняет подход к настройке.

Как это работает на самом деле

Kubelet следит за ресурсами ноды и при пересечении пороговых значений начинает вытеснение (eviction), чтобы спасти саму ноду. Отслеживаются:

Пороги по умолчанию — примерно так:

PLAINTEXT
memory.available < 100Mi
nodefs.available < 10%
imagefs.available < 15%
nodefs.inodesFree < 5%
Нажмите, чтобы развернуть и увидеть больше

Различают жёсткие пороги (вытеснение немедленно) и мягкие (вытеснение после evictionSoftGracePeriod, с корректным завершением пода).

Как выбирается жертва

Порядок такой:

  1. Сначала — превысившие свои requests. Под, потребляющий меньше, чем запросил, считается «в рамках договора» и защищён.
  2. Затем — по классу QoS: сначала BestEffort, потом Burstable, в последнюю очередь Guaranteed (см. задачу 3).
  3. Внутри группы — по приоритету (PriorityClass) и величине превышения.

Вот и ответ на «почему невиновные»: если под относится к BestEffort (нет requests), он будет выселен раньше того, кто реально забил диск, но имеет Guaranteed. Kubelet спасает ноду, а не ищет виноватого.

Что считается за под при дисковом давлении

Для дисковых порогов kubelet учитывает:

Отсюда и типовые виновники: приложение, пишущее логи в файл внутри контейнера; забытый emptyDir без лимита; скачанные во временный каталог файлы.

Постоянные тома (PV) в этот счёт не входят — они живут отдельно.

Eviction против OOMKilled

Эти два состояния постоянно путают:

EvictedOOMKilled
Кто инициируетkubeletядро (OOM killer)
ПричинаДавление на ресурсы нодыКонтейнер превысил свой лимит памяти
Что происходитПод удаляется, планируется зановоКонтейнер перезапускается на месте
Виден вstatus.phase: Failed, reason EvictedlastState.terminated.reason: OOMKilled
ЛечениеРесурсы ноды, requestsЛимит контейнера, утечка

Подробнее про второе — в задаче 5.

Ответ

Kubelet выселяет не «виновного», а того, кого дешевле и безопаснее выселить: сначала поды, превысившие свои requests, затем по классам QoS начиная с BestEffort. Под без requests, ничего не писавший на диск, окажется первым кандидатом — просто потому, что он ничего не запросил и потому ничем не защищён.

Что с этим делать

Диагностика

BASH
# Состояние ноды: ищем условия давления
kubectl describe node node-1 | grep -A8 Conditions
# MemoryPressure   False
# DiskPressure     True     ← вот оно
# PIDPressure      False

# Выселенные поды по кластеру
kubectl get pods -A --field-selector status.phase=Failed

# Причина по конкретному поду
kubectl describe pod evicted-pod | grep -A5 "Status\|Message"

# Что занимает место на ноде
kubectl debug node/node-1 -it --image=busybox -- df -h /host
Нажмите, чтобы развернуть и увидеть больше

Защита рабочих нагрузок

Настройка ноды


Дальше: Задача 20. Обновление кластера и умирающие API.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша