Назад | Перейти на главную страницу

Точка входа в сценарий Bash (PID = 1) убивает подпроцесс `tail` ТОЛЬКО если там была фальшивая ловушка (которая НИЧЕГО не делает)

Я столкнулся со странным поведением в моем Bash сценарий, у меня есть это Bash скрипт, который работает с PID 1 (это entrypoint для Docker контейнер, если вы не знакомы с Docker, я предполагаю, что вы можете игнорировать эту информацию).

Когда я запускаю следующий сценарий, SIGTERM завершает все очень быстро, и вроде бы все в порядке (имейте в виду, что sshd сервис не существует! Вся моя система запускает только этот сценарий, который запускается tail не более того, но до сих пор это не проблема).

#!/bin/bash

trap "pkill sshd" SIGTERM

export PATH=/usr/local/samba/bin/:/usr/local/samba/sbin/:$PATH

if [ -f /usr/local/samba/etc/smb.conf ]; then
        exec /usr/local/samba/sbin/samba -i
else
        tail -f /dev/null & wait ${!}
fi

Проблема возникает, когда я удаляю это trap. Теперь моя система зависает, и похоже, что tail все еще работает и по какой-то причине не заканчивается (если вы знакомы с Docker, Docker ждет 10 секунд, а затем убивает контейнер, потому что он не ответил на SIGTERM(опять же, если вы не знакомы с Docker, проигнорируйте эту информацию).

#!/bin/bash

export PATH=/usr/local/samba/bin/:/usr/local/samba/sbin/:$PATH

if [ -f /usr/local/samba/etc/smb.conf ]; then
        exec /usr/local/samba/sbin/samba -i
else
        tail -f /dev/null & wait ${!}
fi

Может ли кто-нибудь объяснить мне, в чем именно проблема? Почему это подделка trap заставляет все работать (хотя практически ничего не делает, но работает, потому что просто есть).

Я просто хочу упомянуть, что использование пустого trap: trap "" SIGTERM не помогает, в ловушке должно быть что-то, чтобы работать (даже если ничего не делает).

Надеюсь, что кто-то может мне помочь, спасибо!

Вы не предоставили свой Dockerfile и неясно, как вы отправляете SIGTERM сигнал к контейнеру.

Однако вот что я придумал, пытаясь воспроизвести вашу проблему:

Мой Dockerfile:

FROM ubuntu
ADD ./entrypoint.sh /opt/entrypoint.sh
# Using the exec form here, so that the process is assigned PID 1.
ENTRYPOINT ["/opt/entrypoint.sh"]

Контейнер сборки:

$ docker build -f Dockerfile -t test_image .

Не забывайте перестраивать контейнер каждый раз, когда вы меняете сценарий точки входа.

Запустите контейнер с помощью этой команды:

$ docker run --rm -it --name test_trap test_image

Теперь посмотрим, что происходит при каждом запуске.

1) С trap линия в вашем Bash сценарий:

# The main process will receive SIGTERM, trap it and exit.
$ docker stop test_trap

# The main process will receive SIGTERM, trap it and exit.
$ docker kill -s=TERM test_trap

# The main process will receive SIGKILL and will be stopped immediately.
$ docker kill -s=KILL test_trap

2) Без trap линия:

# The main process will receive SIGTERM which will be ignored.
# After a grace period (10s by default) it will receive SIGKILL and will be stopped.
$ docker stop test_trap

# The main process will receive SIGTERM which will be ignored.
# Container will continue running.
$ docker kill -s=TERM test_trap

# The main process will receive SIGKILL and will be stopped immediately.
$ docker kill -s=KILL test_trap

Причина в том, что ядро ​​обрабатывает процесс с помощью PID 1 специально и не убивает процесс получения SIGTERM сигнал (а также SIGINT).

Дополнительная информация по этому вопросу:

Любой процесс может зарегистрировать свои собственные обработчики для TERM и использовать их для выполнения очистки перед выходом. Если процесс не зарегистрировал пользовательский обработчик сигналов, ядро ​​обычно возвращается к поведению по умолчанию для сигнала TERM: завершение процесса.

Однако для PID 1 ядро ​​не вернется к поведению по умолчанию при пересылке TERM. Если ваш процесс не зарегистрировал свои собственные обработчики (чего нет в большинстве процессов), TERM не повлияет на процесс.

Источник - https://engineeringblog.yelp.com/2016/01/dumb-init-an-init-for-docker.html

ОБНОВИТЬ

Я пока не могу комментировать, поэтому оставлю комментарий здесь. Это то же самое PID 1 проблема. С обоими -d и -td обработка сигналов работает должным образом: TERM игнорируется, так как процессу точки входа назначается PID 1, в то время как KILL завершает процесс. Если вы добавите trap линия, затем TERM сигнал будет перехвачен в обоих случаях. Если это не работает для вас по каким-либо причинам, вы должны опубликовать свой Dockerfile, точные команды, которые вы выполняете, и соответствующим образом обновите свой вопрос.

Собственно добавление t параметр (для выделения tty) при запуске контейнера решает проблему. Я управлял им с -d параметр, а теперь с -td.

Не знаю почему, но оно сработало. Было бы здорово, если бы кто-нибудь мог объяснить, почему это происходит.