Траблшутинг Init-процесса в Docker: tini, dumb-init и проброс сигналов SIGTERM
- Команда
docker stopвыполняется ровно 10 секунд и убивает контейнер принудительно сигналомSIGKILL. - Внутри контейнера накапливаются сотни зомби-процессов (состояние
[defunct]илиZвps). - Приложение на Node.js, Python или Java игнорирует сигнал
SIGTERMи не успевает корректно закрыть соединения с БД (Graceful Shutdown).
1. Причина проблемы: Специфика процесса PID 1 в Linux
В ядре Linux процесс с идентификатором PID 1 не имеет стандартных обработчиков сигналов по умолчанию. Если приложение явно не регистрирует перехват SIGTERM, ядро полностью игнорирует сигнал остановки.
2. Использование встроенного в Docker механизма Init (--init)
Docker содержит встроенный легковесный init-процесс Tini:
docker run -d --name my_app --init my_node_app:latest3. Интеграция Tini напрямую в Dockerfile
FROM alpine:3.19
RUN apk add --no-cache tini
WORKDIR /app
COPY . .
# Запуск Tini в качестве PID 1
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["node", "server.js"]4. Использование dumb-init для Debian/Ubuntu образов
FROM debian:12-slim
RUN apt-get update && apt-get install -y --no-install-recommends dumb-init
WORKDIR /app
COPY . .
ENTRYPOINT ["dumb-init", "--"]
CMD ["python3", "app.py"]5. Проверка корректного синтаксиса CMD (Exec Form vs Shell Form)
Всегда используйте синтаксис массива JSON (Exec Form):
# ПРАВИЛЬНО (Exec Form: приложение становится прямым потомком init):
CMD ["node", "app.js"]
# НЕПРАВИЛЬНО (Shell Form: запускается /bin/sh -c, блокирующий сигналы):
CMD node app.js Частые вопросы (FAQ)
Что такое Zombie Reaping и почему этим должен заниматься PID 1?
Когда дочерний процесс завершается, он остается в таблице процессов как зомби до тех пор, пока родительский процесс не вызовет wait(). Если родитель завершился раньше, осиротевший процесс перепривязывается к PID 1. Tini и dumb-init автоматически вызывают wait() и очищают таблицу процессов.
Как увеличить стандартный таймаут ожидания docker stop?
Используйте флаг -t: docker stop -t 30 <container_id> (ожидание 30 секунд перед отправкой SIGKILL).