LINUX.ORG.RU

bash, docker, sleep

 ,


0

1

Есть bash-скрипт, который запускает чего-то там в background и дальше делает sleep 100000d. Смысл в том, что юзер жмет ctrl+c, скрипт завершает выполнение и фоновые процессы прибиваются.

В докере это не работает. На ctrl+c реакции нет, stop не останавливает (ну точней останавливает тупо прибивая, когда таймаут выходит).

Пробовал: trap, trap с короткими sleep в цикле, trap с sleep в фоне и wait.

Последняя попытка:

    trap 'echo trap 0' 0
    trap 'echo trap 1' 1
    trap 'echo trap 2' 2
    trap 'echo trap 3' 3
    trap 'echo trap 13' 13
    trap 'echo trap 15' 15
    trap 'echo trap INT' INT
    trap 'echo trap STOP' STOP
    trap 'echo trap TERM' TERM
#    trap 'jobs -p | xargs --no-run-if-empty kill' STOP
    
#    sleep 100000d || true
    sleep 1 &
    while wait $!
    do
        sleep 1 &
    done

Ничего не работает. Как это правильно сделать?

Т.е. если упростить, то:

test.sh:

#!/bin/sh -eu

trap 'echo trap INT' INT

sleep 100000d || true

Dockerfile

FROM node:16

WORKDIR /root
COPY test.sh .
CMD ./test.sh
docker build -t test .
docker run --rm --name test test

Тут надо, чтобы он на Ctrl+C среагировал, напечатав что-нибудь и остановившись. Или на docker stop test в соседней вкладке. Хотя кажется это одно и то же.

Запускать docker run -t не предлагать. Оно должно в конечном итоге работать как сервис.

★★★★★

Последнее исправление: Legioner (всего исправлений: 1)

Ответ на: комментарий от vvn_black

Так работает, но мне надо без -it, т.к. оно должно работать сервисом, возможно в составе docker-compose. Смысл в том, чтобы docker stop отрабатывал моментально, а не с таймаутом.

Legioner ★★★★★
() автор топика
Ответ на: комментарий от Legioner

почитай tini, он какие-то аспекты фиксит, но не уверен что этот тоже.

anonymous
()

Реакции нет потому что нет ключей -it. Странно требовать интерактивности, но не включать её.

ox55ff ★★★★★
()
Ответ на: комментарий от anonymous

Потому что он не нужен. Уверен, автор не сможет внятно объяснить зачем он ему и почему без него хуже. Просто прочёл где-то в инете что докер модный.

firkax ★★★★★
()

Запусти в скрине, потом заверши скрин.

chenbr0
()
Ответ на: комментарий от WitcherGeralt

На случай, если не очевидно, вот пояснение:

The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL. The first signal can be changed with the STOPSIGNAL instruction in the container’s Dockerfile, or the --stop-signal option to docker run

https://docs.docker.com/engine/reference/commandline/stop/

Всё же, лорчик теперь ресурс яблочно-виндузотный. Выше всего пара осмысленных комментариев.

WitcherGeralt ★★
()
Ответ на: комментарий от firkax

Ctrl+C это интерактивная штука. Для демонов она разумеется не работает.

Это это обычный сигнал, который можно послать хоть демону, хоть ангелу.

urxvt ★★★★★
()

внутри контейнера тебе не надо отправлять в бэкграунд. делай работу в фореграунде.

у тебя несколько процессов в одном контейнере? ты что-то делаешь не так. распили на несколько контейнеров. (или прикостыливай инит в контейнер. но я бы так не стал делать)

aol ★★★★★
()

раз не хочешь попрбовать tini, попробуй использовать форму ENTRYPOINT/CMD c квадратными скобками.

может быть там промежуточный шел появляется? (сделай ps)

но это пальцем в небо

anonymous
()
Ответ на: комментарий от garik_keghen

Каким образом SIGTERM мешает реализации graceful shutdown? Не вводи в заблуждение. Это как раз и есть основной сигнал для этого, выше цитата из документации докера тебе на это прозрачно намекает.

WitcherGeralt ★★
()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от aol

у тебя несколько процессов в одном контейнере? ты что-то делаешь не так

Есть же альтернативная парадигма: дробление по сервисам, а не по процессам

zolden ★★★★★
()
Ответ на: комментарий от aol

Любой баш скрипт запускает кучу процессов. Сдурели уже со своей религиозностью. Так, не так. Задача простейшая. Получить сигнал, потушить всё остальное. Скрипт работает как есть для обычного использования. Понадобилось его засунуть в контейнер. Не хочу я его распиливать ещё на какие-то процессы, мне надо просто чтобы в контейнере он работал. Он и работает, просто стопается долго и не совсем gracefully (хотя по большому счёту пофиг, но хочется красиво).

Legioner ★★★★★
() автор топика
Ответ на: комментарий от urxvt

Нет, Ctrl+C это не сигнал. Перед тем как возражать мне чем-то типа «Ctrl-C = SIGINT = сигнал», почитай аккуратнее, как именно работает Ctrl+C - на каком этапе и как именно он превращается в SIGINT и кому конкретно этот SIGINT отправляется.

firkax ★★★★★
()

Лега, сорри, что чуть-чуть не по теме.

  1. Прошу проверить пользователя @ArtSh на соответствие правила: «использование одного логина более чем одним пользователем;».

  2. Вот ещё, специально для @Aceler: https://www.youtube.com/watch?v=BTKdF8yOSxc (здесь же можно сделать отсылку к пользователю ЛОРа, которого сдали в деле «сети»).

anonymous
()
Ответ на: комментарий от Legioner

Мб тебе лучше подойдёт LXC?

Если очень хочется именно в докере, то это вполне легально, но придётся взять не bash, а например питон.

https://docs.python.org/3/library/asyncio-subprocess.html

Или просто используй готовый супервизор.

https://docs.docker.com/config/containers/multi-service_container/

WitcherGeralt ★★
()
Ответ на: комментарий от WitcherGeralt

сорри, что не по теме, но ты однозначно прав про телефон и его «удобство для большого брата». я к тому, что этим он реально пользуется. пруфы? пруфы по аналогии с пейджерами «без суда и следствия» в период чеченского конфликта. не одно и то же это с нынешнем временем? возможно, но это не относится к сути, так как люди и возможности те же, в плане «без решения суда».

anonymous
()
Ответ на: комментарий от firkax

Ну и как же? В чем разница между тем что программе его баш по С-С пошлет и Докер пошлет при остановке контейнера?

urxvt ★★★★★
()
Ответ на: комментарий от anonymous

Не, не пальцем в небо. Без скобок как раз режим shell.

Но ведь ему ещё и какие-то демоны запускать и грохать. Черт его пойми, что он хочет.

WitcherGeralt ★★
()
Ответ на: комментарий от urxvt

Первая твоя ошибка: баш в доставке до программы известия о ctrl+c никак не участвует. Говорю же, почитай как оно работает. Подсказка: этот код находится в ядре ОС.

Докер пошлет при остановке контейнера

Причём тут остановка контейнера? Автор хочет чтобы Ctrl-C работало.

Так то конечно понятно как сделать всё хорошо, но у автора изначально неверный подход (спрятать и закостылить), так что пусть страдает.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 3)
Ответ на: комментарий от urxvt

там кажетс если отправлено по ктрл-ц фореграундоному то терминальный то ли драйвер то ли что распространит его на всю группу(процессу + чайлдам). если же отправить не через ктрл-ц а из программы, то его получит только пид которому отправили.

anonymous
()
Ответ на: комментарий от firkax

Причём тут остановка контейнера? Автор хочет чтобы Ctrl-C работало.

Нет, автор хочет, чтобы работала остановка контейнера. Ctrl+C в докере (без -t) делает именно это.

Legioner ★★★★★
() автор топика
Ответ на: комментарий от Legioner

пид=1 не киллается если нет обработчика сигинт. у тебя твой скрипт ловит вообще сигинт? не знаю как это проврить.

тини ты пробовать не хочешь, скобки тоже. хз.

anonymous
()
Ответ на: комментарий от Legioner

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

anonymous
()

извините что не по теме

мне вот что непонятно, если докернутому процессу сделать килл, то куда репарентятся его чайлды? пид=1 же нету

anonymous
()
Ответ на: комментарий от Legioner

Тебе уже сто раз объяснили, что нужно использовать режим exec (убрав скобки) и супервизор: supervisord или tini. Как юзать супевизор я тебе скинул ссылку, там всё есть, скопипастишь без вольностей и будет работать, как написать велосипедный супервизор я тоже уже показал.

Чего тупишь?

WitcherGeralt ★★
()
Последнее исправление: WitcherGeralt (всего исправлений: 1)
Ответ на: комментарий от Legioner

Ну, лови сигнал и рассылай sigint всем вручную скриптом (у kill есть такая опция), потом wait. Но можешь задеть так что-то лишнее (по сравнению с нативным ctrl+c) и опять будет некрасиво. Без управляющего терминала один в один поведение не повторить, потому что само наличие управляющего терминала у процесса - считай флаг (да/нет), от которого зависит что-то. Если же терминала изначально нет то его просто нет у всех. Если ты уверен что все child процессы не трогают свою привязку к терминалу то можешь просто разослать SIGINT всем (`kill -INT -1`) и сделать `wait`.

firkax ★★★★★
()
Ответ на: комментарий от anonymous

там pid1 это стартовый процесс, у большинства инет-копипастеров это баш

если убить его то контейнер выключится

firkax ★★★★★
()
Ответ на: комментарий от firkax

чайлды которые он породил-то куда денутся? они должны прикрепляться к pid=1, но именно его мы и терминировали. не к хостовому же pid=1 их репарентить? тогда куда? мутная штука этот докер-шмокер

anonymous
()
Ответ на: комментарий от anonymous

Не факт, что это критично. И в любом случае, задачу запуска фоновых процессов нужно решать цивилизованно, а не портянками на баше.

WitcherGeralt ★★
()
Ответ на: комментарий от anonymous

Чайлды выключатся вместе с контейнером (SIGKILL).

man pid_namespaces

Это фича не докера, если что, а ядра.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)

Приходит как-то маковод-ламер с башем и докером на лор и говрит: «я страдаю». А лор ему отвечает: хорошо.

anonymous
()
Ответ на: комментарий от firkax

Спасибо, тут я, действительно, заблуждался. Но я имел ввиду, что для процесса получающего сигнал разницы нет, кто был инициатором сигнала. Ему то он прилетает от ядра в любом случае.

urxvt ★★★★★
()

anonymous был прав, проблема была в промежуточном шелле. CMD "./test.sh" сначала запускает первый bash, который потом запускает bash -c «./test.sh». Сигналы приходят первому bash-у, который с ними ничего не делает, т.к. не имеет отношения к выполняемому скрипту.

Решение, соответственно, изменить на CMD ["./test.sh"]. Теперь сигналы приходят нужному bash-у, который их уже спокойно ловит и обрабатывает.

На всякий случай вот как надо правильно спать, чтобы обработать сигнал:

sleep 1 &
while wait $!
do
    sleep 1 &
done
Legioner ★★★★★
() автор топика
Ответ на: комментарий от WitcherGeralt

Никак не мешает, я не об этом, а ты тригеришься не поняв о чем я написал.

garik_keghen ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.