- Вопрос или проблема
- Ответ или решение
- Проблема с обработкой сигналов в Docker при использовании PHP
- Введение
- Описание проблемы
- Основная проблема
- Вот что происходит в ваших скриптах:
- Проблема с обработкой сигналов в образе php:8.3-fpm
- Решения
- 1. Изменение уровня доступа в контейнере
- 2. Использование образа Alpine
- Заключение
Вопрос или проблема
У меня есть скрипт, который должен запускать другую программу в цикле. Но я хотел бы захватить сигналы, чтобы остановить цикл корректно.
Вот мой воспроизводимый код:
loop.sh
:
#!/bin/bash
COMMAND="logic.sh"
terminate=false
trap 'terminate=true' SIGTERM SIGINT
while true; do
if $terminate; then
echo "Получен сигнал завершения, жду завершения текущего процесса..."
wait
echo "Процесс завершен. Выход..."
exit 0
fi
$COMMAND &
wait $!
done
logic.sh
:
#!/bin/bash
sleep 5
date +%s
Dockerfile
:
# FROM debian
FROM php:8.3-fpm
ADD loop.sh logic.sh /usr/local/bin/
CMD ["loop.sh"]
compose.yml
:
services:
app:
build: .
entrypoint: ''
init: true
Чтобы протестировать это, я запускаю docker compose up --build
; а в другом терминале docker compose stop
.
Если вы видите Получен сигнал завершения, жду завершения текущего процесса...
, затем временную метку, значит это работает.
При использовании FROM php:8.3-fpm
это не работает, как ожидалось… но при использовании FROM debian
— да.
Почему это работает по-другому? Как я могу заставить это работать с FROM php:...
?
Спасибо
Ответ или решение
Проблема с обработкой сигналов в Docker при использовании PHP
Введение
При разработке контейнеризованных приложений часто возникает необходимость обрабатывать системные сигналы, такие как SIGTERM или SIGINT, чтобы корректно завершать процессы внутри контейнера. В данной статье мы обсудим проблему, с которой вы столкнулись при использовании скриптов в Docker с различными базовыми образами, а также предложим пути её решения.
Описание проблемы
У вас есть скрипт loop.sh
, который запускает другой скрипт logic.sh
в цикле и должен корректно завершать свою работу при получении сигнала остановки. Скрипт работает корректно, когда базовым образом является debian
, но не выполняет обработку сигналов должным образом, когда основным образом является php:8.3-fpm
. Причина этой разницы заключается в том, как различные образы Docker обрабатывают сигналы и процессы.
Основная проблема
Используя образ php:8.3-fpm
, ваш скрипт, прописанный в CMD
, может быть заменен на фоновый процесс, что не позволяет ему адекватно обрабатывать сигналы. Образ php-fpm
реализует свою собственную систему,, которая может игнорировать или не передавать сигналы дочерним процессам.
Вот что происходит в ваших скриптах:
loop.sh
использует механизмtrap
для захвата сигналов и установки флагаterminate
, что позволяет корректно завершить текущий процесс.- При отправке сигнала через
docker-compose stop
, контейнер получает сигнал, который в обычном случае должен вызывать обработку вloop.sh
.
Проблема с обработкой сигналов в образе php:8.3-fpm
-
Побочный процесс:
php-fpm
запускает свои собственные процессы. Когда вы запускаете ваш скрипт черезCMD
, он не становится «верхним» (или PID 1) процессом, который мог бы обрабатывать сигналы должным образом. -
Необработанные сигналы: В процессе работы
php-fpm
может игнорировать или обрабатывать сигналы другими способами, что нарушает вашу логику обработки сигналов вloop.sh
.
Решения
1. Изменение уровня доступа в контейнере
Для того чтобы ваш скрипт loop.sh
мог корректно обрабатывать сигналы, необходимо сделать его "верхним" процессом в контейнере. Это можно сделать, используя параметр --init
в вашем docker-compose.yml
, как уже указано, но также важно убедиться, что в качестве entrypoint
установлен именно ваш скрипт, а не php-fpm
.
Пример Dockerfile:
FROM php:8.3-fpm
COPY loop.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/loop.sh
CMD ["/usr/local/bin/loop.sh"]
В docker-compose.yml
:
services:
app:
build: .
entrypoint: ["/usr/local/bin/loop.sh"]
init: true
2. Использование образа Alpine
Если поведение php-fpm
становится слишком сложным, можно рассмотреть использование образа на основе Alpine, который может быть более легковесным и хорошо управляет сигналами:
FROM php:8.3-fpm-alpine
COPY loop.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/loop.sh
CMD ["/usr/local/bin/loop.sh"]
Заключение
Корректная обработка сигналов в контейнерах Docker является важной частью обеспечения их стабильности. При работе с образом php:8.3-fpm
необходимо учитывать специфику работы с фоновыми процессами и обработкой сигналов. Приведенные выше рекомендации помогут вам адаптировать ваш код и скрипты для корректной работы в Docker. Если у вас остались вопросы или требуется дополнительное объяснение, не стесняйтесь обращаться.