Траблшутинг зомби-процессов (defunct) внутри Docker-контейнеров
- Внутри контейнера накапливаются сотни процессов со статусом
Zили[command] <defunct>в выводеps aux. - Исчерпание лимита системных дескрипторов процессов ядра (
kernel.pid_max), невозможность запустить новые процессы (ошибкаfork: Cannot allocate memory). - Контейнер зависает при остановке и не реагирует на команду
docker stopв течение 10 секунд (падает по SIGKILL).
1. Выявление процессов-зомби внутри запущенного контейнера
docker exec -it <container_name> ps aux | grep -i defunct
# Проверка количества занятых PID на уровне хоста
cat /sys/fs/cgroup/pids/docker/<container_id>/pids.current2. Решение через встроенный механизм Docker Init (флаг --init)
Docker содержит встроенный легковесный init-процесс (Tini), перехватывающий сигналы и собирающий завершившиеся дочерние потоки (reaping dead children):
docker run -d --name my-service --init my-image:latest3. Настройка Tini в Docker Compose
Добавьте директиву init: true в блок сервиса:
version: "3.8"
services:
worker:
image: python-worker:latest
init: true
restart: always4. Интеграция dumb-init / tini напрямую в Dockerfile
Если образ запускается в средах Kubernetes или старых версиях Docker без поддержки флага --init:
FROM node:18-alpine
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"] Частые вопросы (FAQ)
Почему процессы переходят в состояние defunct внутри контейнера?
В Linux процесс с PID 1 обязан собирать коды возврата завершившихся дочерних процессов через системный вызов waitid()/waitpid(). Обычные серверные приложения (Node.js, Python, Java) не реализуют эту логику и оставляют зомби-структуры в таблице процессов ядра.
Почему контейнер долго завершается при выполнении docker stop?
Если приложение с PID 1 не перехватывает сигнал SIGTERM, ядро не передает его по умолчанию дочерним процессам. Docker ждет 10 секунд по таймауту и принудительно убивает контейнер через SIGKILL.