Выберите продукт

Kubernetes eviction и node pressure: как разруливать DiskPressure/MemoryPressure без сюрпризов

Разбираем, почему kubelet запускает eviction при node pressure: MemoryPressure, DiskPressure и нехватке ephemeral storage. Покажу, где искать симптомы, как читать kubectl describe node, чем отличаются nodefs и imagefs и как настроить пороги eviction, чтобы избежать массовых перезапусков.
Kubernetes eviction и node pressure: как разруливать DiskPressure/MemoryPressure без сюрпризов

Когда на ноде заканчивается критический ресурс, Kubernetes (точнее, kubelet) обязан защитить саму ноду и системные компоненты. Для этого в kubelet есть eviction manager — механизм, который отслеживает давление на ресурсы (node pressure) и при достижении порогов начинает выселять (evict) поды.

Важно: eviction — это не «ошибка планировщика», а осознанная реакция kubelet на локальную ситуацию. Кластер в целом может выглядеть «здоровым», но одна нода упрется в память или диск и начнет выталкивать нагрузки.

В эксплуатации чаще всего встречаются три сценария:

  • MemoryPressure — заканчивается доступная память на ноде; kubelet может эвиктить менее приоритетные поды, чтобы не упал сам узел.
  • DiskPressure — заканчивается место (или иноды) на файловых системах, связанных с контейнерами/подами, включая логи.
  • Нехватка ephemeral storage — частный случай дискового давления, когда поды раздувают writable layer, логи или emptyDir.

Какие «давления» бывают: MemoryPressure, DiskPressure и PIDPressure

С точки зрения Node Conditions kubelet может выставлять несколько состояний. В контексте диагностики eviction нас интересуют:

  • MemoryPressure=True — на ноде недостаточно memory.available.
  • DiskPressure=True — на ноде недостаточно места или инодов на важных FS (nodefs/imagefs).
  • PIDPressure=True — исчерпаны PID (слишком много процессов).

При этих состояниях kubelet может запрещать запуск новых подов и/или запускать eviction, чтобы вернуть ноду в рабочее состояние.

Снаружи это часто выглядит как «поды сами перезапускаются» или «Deployment не держит реплики», но первопричина обычно локальная: память, диск или иноды на конкретной ноде.

Где искать признаки: kubectl describe node и события eviction

Первый инструмент — kubectl describe node. Он показывает Node Conditions, события от kubelet и иногда подсказки по типу FS.

kubectl describe node NODE_NAME

Что смотреть внутри вывода:

  • Conditions: строки про MemoryPressure, DiskPressure, PIDPressure.
  • Events: сообщения вида EvictionThresholdMet, Evicted, упоминания imagefs/nodefs или ephemeral-storage.

Дальше — события по конкретному поду, который «выселили»:

kubectl describe pod POD_NAME -n NAMESPACE

Типичные маркеры:

  • Reason: Evicted
  • Message: например The node was low on resource: ephemeral-storage или memory

Вывод kubectl describe node с условиями DiskPressure и MemoryPressure

nodefs vs imagefs: почему важно понимать, где «кончилось место»

В событиях и настройках eviction вы встретите термины nodefs и imagefs. Это ключ к пониманию, кто «съел диск»:

  • nodefs — FS, где живут данные подов: writable layer контейнеров, логи, emptyDir, а также данные в зоне /var/lib/kubelet (часто это корневой раздел или отдельный mount под kubelet).
  • imagefs — FS, где живут образы контейнеров (часто /var/lib/containerd или аналог для runtime). Иногда совпадает с nodefs, иногда вынесена отдельно.

Практический смысл простой:

  • Если давление на imagefs — виноваты образы: много версий, большие base images, неэффективная сборка, GC не успевает.
  • Если давление на nodefs — чаще виноваты логи, разросшиеся emptyDir, кеши приложений, временные файлы и дампы.

При одинаковом симптоме DiskPressure=True план действий будет разный: чистить образы или ограничивать/переносить запись подов.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Как kubelet решает, кого выселять: приоритеты, QoS и что реально работает

Eviction manager выбирает жертвы не случайно. Самая предсказуемая логика строится вокруг QoS-классов:

  • BestEffort — поды без requests/limits; выселяются первыми.
  • Burstable — есть requests (и/или limits); обычно вторые в очереди.
  • Guaranteed — requests = limits для всех контейнеров; стараются сохранять до последнего.

Отсюда частая причина «неожиданного» eviction в проде: критичная нагрузка без resources.requests и resources.limits выглядит для kubelet как «дешевая» и улетает первой при любой турбулентности.

Для диска дополнительно учитываются requests/limits по ephemeral-storage и фактическое потребление writable layer, логов и emptyDir.

Ephemeral storage: что это в реальности и почему оно внезапно заканчивается

Ephemeral storage — это не отдельный диск, а суммарное «временное» потребление на ноде, связанное с подами:

  • writable layer контейнера
  • emptyDir
  • логи контейнеров
  • временные файлы внутри FS контейнера

Самые частые источники перерасхода:

  • приложение пишет бесконечные логи в stdout/stderr; на ноде копятся файлы логов контейнеров
  • генерация временных файлов (архивы, экспорты, превью) в /tmp и похожих каталогах
  • emptyDir используется как кеш без политики очистки
  • init-контейнер скачивает большие артефакты и оставляет их в writable layer

Настройка kubelet eviction thresholds: что можно крутить и как не выстрелить в ногу

В kubelet есть параметры, которые определяют пороги эвикшена. Конкретный способ задания зависит от дистрибутива и способа установки (kubeadm/managed/k3s и т.д.), но смысл один: задать «подушку», до которой kubelet терпит, и после которой начинает освобождать ресурсы.

Ключевые группы сигналов (их названия встречаются и в конфиге kubelet, и в событиях):

  • memory.available — доступная память
  • nodefs.available, nodefs.inodesFree — место и иноды на nodefs
  • imagefs.available, imagefs.inodesFree — место и иноды на imagefs

Обычно пороги делят на «мягкие» (soft) и «жесткие» (hard), плюс есть период перехода давления (evictionPressureTransitionPeriod) и grace-периоды для soft eviction. Практическая идея такая:

  • Hard — «красная линия»: достигли, начинаем eviction быстро.
  • Soft — «желтая зона»: даем время на самоисцеление (GC образов, завершение задач), но при затяжном давлении тоже выселяем.
# Пример структуры (обобщенно): реальные ключи задавайте так, как принято в вашем дистрибутиве kubelet
# evictionHard:
#   memory.available: "500Mi"
#   nodefs.available: "10%"
#   imagefs.available: "10%"
# evictionSoft:
#   memory.available: "1Gi"
# evictionSoftGracePeriod:
#   memory.available: "1m"

Что важно в проде:

  • Слишком «агрессивные» пороги приводят к частым eviction даже при нормальной нагрузке (особенно на небольших нодах).
  • Слишком «мягкие» пороги опасны тем, что нода дойдет до состояния, когда уже страдают системные демоны, runtime и сам kubelet.
  • Если imagefs и nodefs разделены, пороги стоит настраивать для обоих. Иначе можно получить DiskPressure из-за образов при «пустом» nodefs.

Диагностика DiskPressure: быстро понять, образы или данные подов

Алгоритм, который обычно экономит часы:

  1. Проверить события на ноде: kubectl describe node, найти упоминания nodefs/imagefs и тип ресурса (ephemeral-storage, inodes).

  2. Зайти на ноду и посмотреть место и иноды:

df -h
df -i
  1. Проверить, что раздуто в /var/lib/kubelet и каталоге runtime (пример для containerd):

du -xhd1 /var/lib/kubelet 2>/dev/null | sort -h
du -xhd1 /var/lib/containerd 2>/dev/null | sort -h

Практические примечания:

  • Ключ -x у du помогает не уходить в другие файловые системы (полезно, если есть отдельные монтирования).
  • Если уперлись в иноды (df -i), виноваты могут быть миллионы мелких файлов (кеш, временные каталоги, некорректная ротация).

Если подозрение падает на логи контейнеров (nodefs), проверьте лимиты дескрипторов и наблюдаемость: при бурном логировании легко упереться сразу в несколько «узких мест» на ноде. По теме лимитов полезен разбор про fd, nofile и inotify на Linux.

Диагностика MemoryPressure: отличаем eviction от OOMKill

MemoryPressure легко перепутать с OOMKill внутри контейнера. Разница важна для лечения:

  • OOMKill — контейнер превысил лимит памяти (cgroup), kernel убил процесс; в событиях пода будет OOMKilled.
  • Eviction по памяти — kubelet видит, что на ноде мало memory.available, и выселяет поды, чтобы спасти ноду; у пода будет Evicted.

Смотрим события и статус:

kubectl describe pod POD_NAME -n NAMESPACE

Если причина именно нодовая, параллельно полезно на самой ноде посмотреть общую картину:

free -m
cat /proc/meminfo | head

И не забывайте: память «едят» не только контейнеры, но и кеши, systemd-службы, агенты мониторинга/логирования, сам runtime.

Диагностика диска и памяти на Linux-ноде: df, du и free

Как предотвратить eviction: практические меры, которые дают эффект

1) Нормализуйте requests/limits и QoS для критичных нагрузок

Если под важный — сделайте его предсказуемым для kubelet:

  • задайте requests (минимум, который нужен стабильно)
  • задайте limits (верхняя граница, чтобы один под не «съел ноду»)
  • для самых критичных — стремитесь к QoS Guaranteed (requests=limits), если это оправдано по цене ресурсов

Это не «магия», но сильно меняет порядок эвикшена и стабильность при всплесках.

2) Ограничьте и измеряйте ephemeral-storage

Если приложение может временно «раздуться», задавайте requests/limits по ephemeral-storage. Иначе kubelet будет реагировать уже постфактум, когда nodefs забит.

Также проверьте политику логирования и ротации на ноде. Очень часто DiskPressure начинается не с данных приложения, а с логов контейнеров.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

3) Следите за imagefs: размер образов и частота обновлений

Большие образы и частые релизы быстро забивают imagefs. Если события указывают на imagefs:

  • уменьшайте образы (меньше слоев, меньше мусора в build-контексте)
  • контролируйте число версий, которые реально нужны на нодах
  • проверьте, что сборщик мусора образов работает в вашем runtime и не отключен политиками

4) Дайте ноде «воздух»: резерв под систему

На небольших нодах давление возникает быстрее, чем кажется. Оставляйте запас под систему и «пульсации» нагрузки, иначе eviction будет повторяться волнами.

Это достигается комбинацией:

  • разумных порогов eviction
  • резервирования ресурсов под систему (в зависимости от вашего стека)
  • контроля плотности подов на ноду

Если у вас приложения с заметными утечками или резкими пиками, полезно включать профилирование на уровне приложения и рантайма. Для PHP-нагрузок, например, может пригодиться разбор slowlog в PHP-FPM для поиска «тяжелых» запросов.

Чеклист: что сделать, когда eviction уже начался

  1. Подтвердить причину: kubectl describe node и kubectl describe pod.

  2. Определить тип давления: MemoryPressure или DiskPressure, а если диск — это nodefs или imagefs (и/или иноды).

  3. На ноде: df -h, df -i, du по ключевым каталогам.

  4. Снять «пожар»: освободить место или память так, чтобы нода вернулась в норму (иногда проще временно вывести ноду из нагрузки).

  5. Починить первопричину: requests/limits, политика логов, контроль ephemeral storage, оптимизация образов, настройка порогов.

Что считать нормой и когда бить тревогу

Единичный eviction раз в месяц при форс-мажоре — бывает. Но регулярные DiskPressure/MemoryPressure — сигнал, что у вас нет запаса или есть неконтролируемый рост потребления (логи, кеши, образы, утечки).

Если eviction повторяется на одних и тех же нодах:

  • проверьте, не «горячая» ли это нода (например, туда постоянно попадают одни и те же типы подов)
  • сравните образы, логи и emptyDir между нодами
  • оцените, не пора ли разделить imagefs и nodefs или пересмотреть размеры дисков и лимиты

Если вы регулярно упираетесь в ресурсы, иногда быстрее и надежнее дать нодам запас (CPU/RAM/диск) и разгрузить «шумные» ворклоады на отдельный пул. Для этого удобно использовать отдельные узлы на VDS, чтобы изолировать критичные сервисы и снизить вероятность каскадных эвикшенов.

Итог

Node pressure в Kubernetes — нормальный механизм самозащиты, а не случайность. Ключ к стабильности: быстро отличать MemoryPressure от DiskPressure, понимать разницу nodefs и imagefs, уметь читать kubectl describe node и держать в порядке requests/limits и лимиты по ephemeral-storage.

Если дисциплинировать QoS, логи и образы, а пороги eviction настроить с учетом размера нод, eviction станет редким исключением, а не постоянной головной болью.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...