Конечно, sleep является заменой для самых сложных процессов.

Этот Dockerfile (как вы можете видеть, используя форму exec, так что выполняется только один процесс и нет дочерних элементов bash):

FROM busybox
CMD ["/bin/sleep", "100000"]

создает бесперебойный контейнер:

docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep

Когда я пытаюсь остановить это:

time docker stop kill-sleep

kill-sleep
real    0m10.449s
user    0m0.021s
sys     0m0.027s

команда истекает за 10 секунд до уничтожения контейнера.

Проблема не в том, что sleep не обрабатывает сигналы, потому что, если я запускаю его на хосте:

sleep 100000
# in another shell
ps faxww | grep sleep
kill -TERM 31333  # the PID

процесс останавливается немедленно.

Возможно, проблема связана с тем, что в контейнере выполняется PID 1, но я еще не видел справочную документацию по этому вопросу.

1 ответ1

3

Когда вы запустите docker stop ... , произойдут некоторые вещи:

  1. docker отправляет SIGTERM в основной процесс контейнера. Процесс может маскировать / игнорировать SIGTERM , и если он это делает (или обрабатывает без прерывания), « ничего » не произойдет.
  2. По истечении времени ожидания (по умолчанию 10 секунд) docker отправляет SIGKILL основному процессу. Этот сигнал не может быть замаскирован процессом, и, таким образом, он немедленно умирает, не имея возможности выполнить процедуру выключения.

В идеале процессы, выполняемые в docker будут своевременно реагировать на SIGTERM , заботясь о любом ведении домашнего хозяйства до его завершения.

Если вы знаете, что процесс либо не выполняет какие-либо служебные действия (например, sleep), либо не будет правильно отвечать на SIGTERM , вы можете указать более короткий (или более длинный) тайм-аут с флагом -t :

-t, --time=10
    Seconds to wait for stop before killing it

Например, в вашем случае вы можете запустить docker stop -t 0 ${CONTAINER} .


Причина, по которой это поведение сигнала отличается, заключается в том, что sleep работает с PID = 1.

Обычно (например: работает с PID!= 1), любой сигнал, с которым процесс явно не имеет дело, приводит к его завершению - попробуйте отправить sleep в SIGUSR1 режим.

Однако при работе с PID = 1 необработанные сигналы игнорируются, в противном случае вы получите панику ядра:

Kernel panic - not syncing: Attempted to kill init!

Вы можете отправить сигнал в Docker-контейнер с помощью инструментов Docker, например:

docker kill -s TERM kill-sleep

Как мы видим, это не дает желаемого эффекта, тогда как это:

docker kill -s KILL kill-sleep

Эксперимент

Dockerfile

FROM busybox
COPY run.sh /run.sh
RUN chmod +x /run.sh
CMD "/run.sh"

run.sh

#!/bin/sh

echo "sleeping"
sleep 100000

Теперь беги

docker build -t kill-sleep .
docker run --rm --name kill-sleep kill-sleep

И это в другом терминале:

docker stop kill-sleep

Мы наблюдаем ту же 10-секундную задержку / тайм-аут.

Решение

Теперь давайте разберемся с SIGTERM . Фоновая обработка и wait sleep связаны с тем, как оболочка POSIX обрабатывает сигналы (подробнее об этом ).

run.sh

#!/bin/sh

die_func() {
        echo "oh no"
        sleep 2
        exit 1
}
trap die_func TERM

echo "sleeping"
sleep 100000 &
wait

Запустите команды еще раз, и мы увидим, что нам нужно!

$ time docker stop kill-sleep
kill-sleep

real    0m2.515s
user    0m0.008s
sys     0m0.044s

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .