Почему ENOSPC бывает при свободных гигабайтах
Ошибка ENOSPC («No space left on device») не всегда означает, что закончились блоки (ёмкость) на диске. В Linux есть второй лимит: количество inode (индексных дескрипторов). Почти каждый объект в файловой системе (файл, каталог, симлинк, сокет) потребляет один inode. Если inode кончились, создать новый файл нельзя, даже если по df -h ещё остаются гигабайты.
Типичная картина: приложение не может писать кэш/сессии, почта не принимает письма, база не создаёт временные файлы, ротация логов ломается, Docker не распаковывает слои. В логах при этом встречаются сообщения вида ENOSPC и упоминания inodes.
Практическое правило: «место закончилось» в Linux может означать блоки, inode или квоты. Здесь разбираем именно случай, когда упёрлись в inode.
Быстрая проверка: df -i и что смотреть в выводе
Начните с проверки inode на всех смонтированных ФС:
df -i
Смотрите колонки IUsed, IFree, IUse%. Если на нужном маунте IUse% близко к 100% (или IFree около нуля), это и есть причина «нет места» при видимом свободном объёме.
Для сравнения проверьте объём:
df -h
Если по df -h свободно, а по df -i inode закончились, значит нужно искать каталоги с огромным количеством мелких объектов.
Как понять, что упёрлись именно в inode
- создание временных файлов падает (кэш, сессии, загрузки);
logrotateне может создать новый файл;- почтовые сервисы не создают файлы очереди;
apt/dnfне распаковывает пакеты;- Docker ругается на распаковку/слои (часто на overlay2).
Где чаще всего «утекают» inode: практические кейсы
1) Логи и log spam мелкими файлами
Inode часто «съедает» не размер логов, а количество файлов: когда приложение пишет отдельный файл на каждое событие/задачу/запрос, либо ротация настроена так, что вместо сжатия или перезаписи появляются тысячи новых файлов.
Проверьте в первую очередь:
/var/logи вложенные каталоги;- кастомные каталоги логов (часто
/srv,/opt,/home); - папки с некорректной ротацией (например, «лес» файлов по шаблону).
2) /tmp, /var/tmp и временные каталоги приложений
Если /tmp расположен на обычном дисковом разделе (не tmpfs) или приложение пишет временные файлы не в /tmp, а в свою папку, мусор может копиться неделями. Особенно опасны сценарии «тысячи мелких файлов» и отсутствие очистки при аварийном завершении.
Правильное решение обычно включает понятный TTL/retention и автоматическую очистку (например, через systemd-tmpfiles), а не «ручную уборку по праздникам».
Чтобы подобные инциденты не превращались в «пожар на весь сервер», удобно выносить шумные каталоги (логи, кэши, Docker data root) на отдельные тома или отдельную машину. Если проект растёт, часто проще перейти на VDS и разнести нагрузку по дискам, чем постоянно ужиматься в одном разделе.
3) Docker: overlay2 и «миллионы маленьких» в слоях
Частый инцидент — docker overlay2 inodes. Контейнеры могут занимать немного места по объёму, но содержать очень много файлов (например, node_modules, кэши пакетных менеджеров, build-артефакты). Если /var/lib/docker лежит на разделе с ограниченным числом inode (особенно на ext4), inode могут закончиться неожиданно быстро.
Уточните, где Docker хранит данные:
docker info
Дальше проверьте inode именно на том маунте, где находится Docker data root, через df -i.
Если активно используете контейнеры в проде, пригодится отдельная статья про контейнерную песочницу и изоляцию: усиление изоляции контейнеров (gVisor/Firecracker).

4) Особенности ФС: ext4 и XFS
На ext4 число inode обычно задаётся при создании файловой системы. В «обычном» сценарии вы не можете просто так «добавить inode» на существующую ext4 без миграции/пересоздания. Поэтому ситуация «inode закончились» на ext4 встречается часто, если раздел изначально проектировали под несколько крупных файлов, а затем начали хранить кэши и контент из миллионов объектов.
В XFS inode создаются динамически, поэтому упереться именно в inode сложнее, но неконтролируемый рост количества файлов всё равно приведёт к проблемам (пусть и иного характера). Практическая мысль одна: лечить нужно причину появления миллионов объектов, а не только последствия.
Как быстро найти, где сожрали inode
Цель — найти каталоги с максимальным числом объектов внутри конкретной файловой системы, где кончились inode. Важно: подсчёт файлов на миллионах объектов может быть долгим и тяжёлым по диску, поэтому идите от общего к частному.
Шаг 1: определить проблемный маунт
df -i
findmnt -T /var/log
findmnt -T /var/lib/docker
findmnt -T /tmp
findmnt -T показывает, на каком разделе находится путь. Искать «пожирателя» нужно именно там, где у вас IUse% близко к 100%.
Шаг 2: прикинуть, кто виноват на верхнем уровне
Если проблемный раздел смонтирован в /var, начните с верхнего уровня и используйте -xdev, чтобы не уходить на другие файловые системы:
cd /var
for d in *; do echo "$d $(find "$d" -xdev -mindepth 1 -print 2>/dev/null | wc -l)"; done | sort -n
Команда может выполняться заметно долго, но обычно даёт быстрый ориентир: какой каталог «вырвался вперёд» по количеству объектов.
Шаг 3: углубляться до конкретной папки
Дальше повторяйте тот же приём внутри лидирующего каталога, пока не дойдёте до конкретного места, где копятся сотни тысяч или миллионы файлов. После этого у вас будет предметный ответ на вопрос «что чистить» и «что чинить в генераторе».
Точечный поиск: доминирующие расширения/имена
Иногда полезно понять, какие типы файлов плодятся. Пример (на миллионах файлов может быть тяжёлым):
find /var/log/app -xdev -type f -printf '%f
' 2>/dev/null | sed 's/.*\.//' | sort | uniq -c | sort -n | tail
Если видите гигантское количество однотипных tmp/cache/log с уникальными именами, значит приложение создаёт мусор и его нужно ограничивать политиками retention или исправлением логики записи.
Если вы размещаете несколько сайтов и приложений, добавьте мониторинг inode на ключевые маунты и держите отдельные каталоги под кэши/временные файлы. На виртуальном хостинге это часто решается дисциплиной хранения и ротацией, а на сервере даёт плюс возможность разнести данные по разделам.
Как освободить inode безопасно: тактика «сначала стабилизируем»
Когда inode на нуле, задача — быстро вернуть системе возможность создавать файлы, не сломав критичные сервисы. После стабилизации уже разбирайтесь с первопричиной и профилактикой.
1) Удаляйте массово и осознанно
Самый быстрый эффект даёт удаление того, что точно можно очищать: временные файлы, кэши, артефакты сборок. Если сомневаетесь, сначала оцените содержимое и возраст, а на проде избегайте «слепых» удалений без понимания источника.
- старые файлы в
/tmpи/var/tmp; - кэши пакетных менеджеров;
- рабочие директории CI/CD (особенно при неудачных сборках);
- дублирующиеся/лишние логи (учитывайте требования хранения и аудит).
2) Если виноват journald или логирование
Когда inode кончились, ошибки логирования часто начинают множиться и усугублять ситуацию. Для journald имеет смысл проверить использование диска и при необходимости сделать «вакуум» (это больше про объём, но иногда помогает снять давление и вернуть управляемость):
journalctl --disk-usage
journalctl --vacuum-time=7d
journalctl --vacuum-size=500M
Если же проблема в миллионах отдельных файлов логов приложения, лечится это не journald, а схемой логирования и корректной ротацией.
3) Если виноват Docker: чистим неиспользуемые объекты
Перед очисткой оцените, что именно съедает место и (косвенно) inode:
docker system df
Дальше начинайте с наиболее безопасных вариантов (не удаляют работающие контейнеры):
docker container prune
docker image prune -a
docker network prune
С volumes будьте аккуратнее: они часто содержат данные. Применяйте только если уверены, что «висячие» тома действительно не нужны:
docker volume prune
И самый радикальный вариант, который обычно быстро возвращает ресурсы, но может снести много кэша и замедлить следующие деплои:
docker system prune -a
Если после очистки проблема повторяется, пересмотрите сборку образов (уменьшайте количество мелких файлов, чистите кэши в слоях) и правила хранения артефактов. Про практичную настройку сетевой части Docker см. также: Docker и firewall: iptables/nftables без сюрпризов.
4) Остановите «производителя» файлов, иначе всё вернётся
Если вы удаляете мусор, а inode снова заканчиваются через минуты, значит есть активный генератор: кривой логгер, бесконечный ретрай, воркер с ошибкой, агент, который спамит файлами. В этом случае иногда правильнее временно остановить сервис, освободить inode и только потом включать после правки конфигурации/кода.
Профилактика: как сделать так, чтобы inode не кончались снова
Изолируйте «мелкофайловые» зоны
Практика, которая спасает от больших инцидентов: вынести потенциально опасные области в отдельные файловые системы/тома. Тогда даже если inode закончатся в одном месте, вся система останется управляемой.
/var/lib/dockerна отдельный раздел под профиль контейнеров;/var/logотдельно или централизованный сбор логов;- кэши и артефакты CI отдельно от системного раздела;
/tmpв tmpfs, если подходит по памяти и вашей модели угроз.
Нормальная retention-политика: логи, кэши, артефакты
- проверьте, что
logrotateреально ротирует нужные файлы и не создаёт «лес» по ошибочному шаблону; - убедитесь, что приложение не пишет «один файл на событие», если это не осознанный дизайн;
- в CI/CD настройте уборку рабочих директорий и кэшей;
- для временных файлов задайте TTL и механизм удаления.
Очистка через systemd-tmpfiles
Для системной уборки временных каталогов используйте systemd-tmpfiles: так политика очистки становится предсказуемой и воспроизводимой. Конкретные правила зависят от путей и ваших требований к хранению, поэтому сначала протестируйте на небоевом окружении и убедитесь, что не удаляете нужные данные.

Мониторинг: алерты не только по диску, но и по inode
Добавьте мониторинг IUse% на ключевые маунты: /, /var, /var/lib/docker, /var/log. Пороговые значения обычно выбирают так, чтобы у вас оставалось время на реакцию (например, предупреждение 70%, критично 85%, аварийно 95%). Это дешёвый контроль, который ловит проблему до падения сервисов.
Когда «лечить нечего»: inode на ext4 нельзя просто добавить
Если вы регулярно упираетесь в inode на ext4, значит файловую систему создавали с неподходящей плотностью inode под ваш профиль данных. В большинстве типовых сценариев «увеличить количество inode на месте» нельзя: нужно мигрировать данные на новый раздел/том, пересоздать ФС с другими параметрами или менять архитектуру хранения (уменьшать число файлов, упаковывать объекты в архивы, переносить часть в БД/хранилище).
Короткий чеклист: inode usage troubleshooting
- Подтвердить проблему:
df -i. - Найти маунт для конкретного пути:
findmnt -T /path. - Определить «каталоги-лидеры» по числу объектов (
find+wc -lс-xdev). - Быстро освободить inode: удалить/почистить мусор (tmp, кэши, артефакты), при необходимости остановить генератор файлов.
- Если Docker: оценить
docker system df, применить prune по ситуации, затем исправить пайплайны/образы. - Сделать профилактику: retention, systemd-tmpfiles, мониторинг inode, изоляция разделов.
Итоги
ENOSPC — это не всегда про гигабайты. Когда кончаются inode, система выглядит «свободной» по df -h, но отказывается создавать файлы. Самый рабочий порядок действий: подтвердить df -i, быстро найти каталоги с миллионами объектов, аккуратно освободить inode и закрепить профилактикой (retention, автоматическая очистка, мониторинг, грамотная разметка).
Если вы держите проекты на виртуальном хостинге или на VDS, заранее добавьте алерты по inode и вынесите «шумные» каталоги (логи, Docker data root, артефакты) на отдельные тома: так инциденты с inode будут локальными и быстрее лечиться.


