Когда на ноде заканчивается критический ресурс, 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

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 план действий будет разный: чистить образы или ограничивать/переносить запись подов.
Как 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— место и иноды на nodefsimagefs.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: быстро понять, образы или данные подов
Алгоритм, который обычно экономит часы:
Проверить события на ноде:
kubectl describe node, найти упоминанияnodefs/imagefsи тип ресурса (ephemeral-storage, inodes).Зайти на ноду и посмотреть место и иноды:
df -h
df -i
Проверить, что раздуто в
/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.

Как предотвратить eviction: практические меры, которые дают эффект
1) Нормализуйте requests/limits и QoS для критичных нагрузок
Если под важный — сделайте его предсказуемым для kubelet:
- задайте requests (минимум, который нужен стабильно)
- задайте limits (верхняя граница, чтобы один под не «съел ноду»)
- для самых критичных — стремитесь к QoS Guaranteed (requests=limits), если это оправдано по цене ресурсов
Это не «магия», но сильно меняет порядок эвикшена и стабильность при всплесках.
2) Ограничьте и измеряйте ephemeral-storage
Если приложение может временно «раздуться», задавайте requests/limits по ephemeral-storage. Иначе kubelet будет реагировать уже постфактум, когда nodefs забит.
Также проверьте политику логирования и ротации на ноде. Очень часто DiskPressure начинается не с данных приложения, а с логов контейнеров.
3) Следите за imagefs: размер образов и частота обновлений
Большие образы и частые релизы быстро забивают imagefs. Если события указывают на imagefs:
- уменьшайте образы (меньше слоев, меньше мусора в build-контексте)
- контролируйте число версий, которые реально нужны на нодах
- проверьте, что сборщик мусора образов работает в вашем runtime и не отключен политиками
4) Дайте ноде «воздух»: резерв под систему
На небольших нодах давление возникает быстрее, чем кажется. Оставляйте запас под систему и «пульсации» нагрузки, иначе eviction будет повторяться волнами.
Это достигается комбинацией:
- разумных порогов eviction
- резервирования ресурсов под систему (в зависимости от вашего стека)
- контроля плотности подов на ноду
Если у вас приложения с заметными утечками или резкими пиками, полезно включать профилирование на уровне приложения и рантайма. Для PHP-нагрузок, например, может пригодиться разбор slowlog в PHP-FPM для поиска «тяжелых» запросов.
Чеклист: что сделать, когда eviction уже начался
Подтвердить причину:
kubectl describe nodeиkubectl describe pod.Определить тип давления: MemoryPressure или DiskPressure, а если диск — это
nodefsилиimagefs(и/или иноды).На ноде:
df -h,df -i,duпо ключевым каталогам.Снять «пожар»: освободить место или память так, чтобы нода вернулась в норму (иногда проще временно вывести ноду из нагрузки).
Починить первопричину: 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 станет редким исключением, а не постоянной головной болью.


