Too many open files в Docker: проверяем лимит процесса и утечку дескрипторов
Контейнер стабильно работает на малой нагрузке, а затем новые соединения падают с Too many open files. Добавление памяти не помогает: ошибка может означать, что процесс исчерпал разрешённое количество открытых файловых дескрипторов. В этот счёт входят не только файлы, но и сокеты.
У лимита nofile есть мягкая и жёсткая границы. Мягкая ограничивает текущую работу процесса, жёсткая задаёт верхнюю границу её обычного повышения. Настройка оболочки хоста не доказывает, что процесс внутри уже запущенного контейнера получил те же значения.
Посмотрим предел из самого окружения
Учебный сервис ниже только печатает лимиты и ждёт. Он не создаёт тысячи соединений и не нагружает внешние службы. Python resource доступен в Linux-образе, а Compose ulimits задаёт предел при создании контейнера.
services:
inspect:
image: python:3.12-slim
ulimits:
nofile:
soft: 4096
hard: 8192
command:
- python
- -u
- -c
- |
import resource
import time
print(resource.getrlimit(resource.RLIMIT_NOFILE), flush=True)
time.sleep(300)
Проверьте конфигурацию docker compose config. При запуске учебного сервиса ожидаемый вывод — (4096, 8192), если Engine допускает эти значения. Изменение YAML требует пересоздания контейнера. Простая команда restart оставит ранее выданные настройки.
Для настоящего процесса проверьте /proc/PID/limits и количество записей в /proc/PID/fd внутри Linux-контейнера. PID должен принадлежать приложению: оболочка, открытая через exec, является другим процессом. Если приложение — PID 1, используйте /proc/1; при наличии init или wrapper сначала найдите PID программы.
Лимит или утечка
Измерьте число дескрипторов после старта, на стабильной нагрузке и после её прекращения. Если число растёт после каждой партии и не возвращается, ищите незакрытые файлы, ответы HTTP-клиента, соединения и курсоры. Поднятый предел лишь отложит следующий сбой.
Если число растёт вместе с одновременно обслуживаемыми соединениями и затем падает, оцените нужный рабочий максимум. Ограничение пула соединений или параллелизма часто полезнее бесконтрольного увеличения nofile. Новый лимит выбирают вместе с памятью и возможностями базы, иначе контейнер сможет открыть больше соединений, чем соседний сервис выдерживает.
Проверьте точную ошибку
На Linux ошибка EMFILE относится к пределу дескрипторов процесса. ENFILE указывает на системное ограничение таблицы открытых файлов. Сообщение библиотечного уровня может скрывать код, поэтому сохраните исходное исключение и момент появления. Одинаковая фраза в пользовательском журнале не всегда означает одинаковый уровень проблемы.
После исправления повторите контролируемую нагрузку и сравните одновременно три величины: число активных операций, дескрипторы и ошибки. Успешный старт с новым YAML доказывает только передачу настройки. Полезный результат — работа под нужной нагрузкой с устойчивым числом ресурсов после её окончания.
В курсе Docker и Docker Compose вы разберёте диагностику процессов, ограничения ресурсов и конфигурацию окружения приложения с PostgreSQL. Откройте программу и научитесь связывать сообщение об ошибке с настройкой контейнера и поведением кода.
Продолжить на практике
- Docker и Docker Compose: контейнеризация приложений ↗
Упакуйте приложение в Docker и запустите его с PostgreSQL через Compose. Образы, сети, тома, диагностика поломок, обновление версий и восстановление данных — с практикой и итоговым проектом.
