Как я могу остановить Docker-контейнер, работающий в режиме сна?

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, но я еще не видел справочную документацию по этому вопросу.

2 ответа

Когда ты бежишь 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

Еще несколько вариантов:

  • добавить--initпереключитесь на команду запуска контейнера. Таким образом, сон не является PID 1, и init делает правильные вещи в TERM.
  • добавить--stop-signal=KILLк команде запуска контейнера. Однако использование KILL как нормальной операции обычно не рекомендуется.
Другие вопросы по тегам