#Симптомы и условия возникновения
В контейнере Docker приложение Node.js не успевает закрыть сервер при docker stop: обработчик SIGTERM не вызывается, активные операции обрываются. Причиной может быть оболочка как PID 1 либо отсутствие обработчика завершения. Для начала проверьте используемую версию среды и точный текст ошибки на копии проекта, не меняя рабочий сервер.
#Причины и как их отличить
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Shell-форма запускаВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | CMD node server.js через /bin/sh -c | Заменить на exec-форму для прямой доставки сигнала. |
| Нет обработчика SIGTERMВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | Node получает сигнал и завершает процесс без закрытия соединений | Установить обработчик и завершать HTTP-сервер штатно. |
| Нехватка времени остановкиВ этой ситуации наблюдается конкретный диагностический признак. Сопоставьте его с журналом ошибки и результатом соответствующей проверки, прежде чем выбирать исправление. | Контейнер остановлен принудительно после тайм-аута | Уменьшить время очистки, согласовать grace period. |
#Пошаговая диагностика и решение
- 1. Создайте тестовый контейнер с той же конфигурациейСохраните Dockerfile и настройки запуска; используйте отдельный контейнер без рабочих данных. Остановите его командой docker stop и посмотрите последние записи журнала, не удаляя рабочий контейнер.
- 2. Проверьте команду контейнера и PID 1Откройте Dockerfile. Вариант
CMD node server.jsзапускает команду через shell, которая может не переслать SIGTERM. Рекомендуемая форма:CMD ["node","server.js"]; для ENTRYPOINT действует тот же принцип.
- 3. Добавьте логируемый обработчик сигналаВ тестовый сервер добавьте
process.once("SIGTERM", shutdown)с вызовомserver.close(). Убедитесь, чтоserver— реальный объект от listen; предусмотрите обработку ошибки и ожидание активных запросов.
- 4. Пересоберите только тестовый образВ каталоге копии Dockerfile выполните сборку с отдельной меткой. Сборка запускает инструкции Dockerfile, поэтому используйте доверенные зависимости и не передавайте секреты в аргументах сборки.
- Терминал с доступом к тестовому Docker; точка — текущий каталог с DockerfileLinux · Терминал (Bash)КомандаТерминал с доступом к тестовому Docker; точка — текущий каталог с Dockerfile.
docker build -t node-graceful-test .
- 5. Запустите проверку завершенияСоздайте тестовый контейнер, запросите пробную страницу и выполните
docker stopпо его имени. Просмотрите журнал: ожидается отметка обработчика и штатное закрытие без SIGKILL. При неуспехе проверьте PID 1 и время ожидания.Linux · Терминал (Bash)С осторожностьюDocker-хост с правами на управление контейнерами; используйте только отдельно созданный тестовый контейнер с этим именем. Ожидается его штатная остановка, а не изменение рабочего приложения.docker stop node-graceful-test-containerКоманда может изменить состояние системы или её настройки. Проверьте параметры и последствия перед запуском.
- 6. Не затягивайте завершение бесконечноНовые запросы после SIGTERM должны прекращаться. Для долгих запросов установите рассчитанное максимальное ожидание; не допускайте зависания shutdown. У Docker настраивается тайм-аут остановки, но он не заменяет обработку сигнала.
- 7. Внедрите после проверкиПеренесите изменения из тестовой копии и остановите/обновите экземпляры через согласованный процесс развёртывания. Если клиенты теряют запросы, откатите образ и исследуйте лог до остановки.
- Пример кода по темеТекстПример для тестовой копии, где app уже существует; фоновые задания и БД требуют собственной последовательности закрытия.
const server = app.listen(3000); // app — уже созданное приложение let closing = false; process.once('SIGTERM', () => { if (closing) return; closing = true; console.log('SIGTERM: закрываем HTTP-сервер'); server.close((err) => { if (err) console.error(err); process.exitCode = err ? 1 : 0; }); });
#Как проверить результат и что делать, если не помогло
При docker stop появляется отметка SIGTERM и завершающая запись приложения, активные ответы успешно заканчиваются в допустимое время.
Если неисправность повторилась, выпишите первый код ошибки и действие, на котором она возвращается. Сравните версию Node.js/npm, рабочий каталог, настройки процесса и журнал тестового запуска. Откатите только внесённые изменения из предварительно сохранённой копии, затем разберите причину на отдельной среде.