Что происходит с другими процессами при выходе из PID1 контейнера Docker?

Рассмотрим следующее, которое запускает sleep 60 в фоновом режиме, а затем завершает работу:

$ cat run.sh 
sleep 60&
ps
echo Goodbye!!!
$ docker run --rm -v $(pwd)/run.sh:/run.sh ubuntu:16.04 bash /run.sh
  PID TTY          TIME CMD
    1 ?        00:00:00 bash
    5 ?        00:00:00 sleep
    6 ?        00:00:00 ps
Goodbye!!!

Это запустит контейнер Docker с bash в качестве PID1. Затем он разветвляет/выполняет процесс sleep, а затем bash завершает работу. Когда контейнер Docker умирает, процесс sleep тоже каким-то образом умирает.

Мой вопрос: каков механизм уничтожения процесса sleep? Я попытался перехватить SIGTERM в дочернем процессе, и, похоже, это не сработало. Я предполагаю, что что-то (либо Docker, либо ядро ​​​​Linux) отправляет SIGKILL при завершении работы cgroup, которую использует контейнер, но я нигде не нашел документации, разъясняющей это.

EDIT Ближе всего к объяснению я пришел к следующей цитате из baseimage- докер:

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

Таким образом, по крайней мере, согласно этому, подразумевается, что при выходе из контейнера ядро ​​отправит SIGKILL всем оставшимся процессам. Но мне все же хотелось бы ясности в том, как это решается (т. е. является ли это особенностью cgroups?), и в идеале было бы неплохо иметь более авторитетный источник.


person Michael Snoyman    schedule 28.09.2016    source источник


Ответы (1)


Хорошо, я, кажется, нашел более веские доказательства того, что на самом деле это ядро ​​​​Linux выполняет завершение. На справочной странице clone(2) есть этот полезный раздел:

CLONE_NEWPID (начиная с Linux 2.6.24)

Первый процесс, созданный в новом пространстве имен (т. е. процесс, созданный с использованием флага CLONE_NEWPID), имеет PID 1 и является процессом «инициализации» для пространства имен. Дети, потерявшие родительские права в пространстве имен, будут переназначены для этого процесса, а не для init(8). В отличие от традиционного процесса инициализации, процесс инициализации пространства имен PID может завершиться, и если это произойдет, то будут завершены все процессы в пространстве имен.

К сожалению, до сих пор неясно, как именно завершаются процессы в пространстве имен, но, возможно, это связано с тем, что, в отличие от обычного завершения процесса, в таблице процессов не остается никакой записи. Как бы то ни было, кажется очевидным, что:

  • Само ядро ​​убивает другие процессы
  • Их не убивают таким образом, чтобы у них был шанс выполнить очистку, что делает его (почти?) идентичным SIGKILL.
person Michael Snoyman    schedule 28.09.2016
comment
Докеры runc могут выполнить очистку, если вы выполняется в пространстве имен hosts pid. - person Matt; 29.09.2016
comment
и ядро ​​отправляет SIGKILL для завершения процессов. - person Matt; 29.09.2016
comment
@ Мэтт Приятно знать. Становится ли ответственность за их получение хост-процессом init, или ядро ​​также удаляет их из таблицы процессов? - person Michael Snoyman; 29.09.2016
comment
Когда в процессе контейнера докеров (docker run --pid host) нет опции NEWPID, ядро ​​не имеет возможности удалить/убить процессы самостоятельно. Если бы Docker не удалось очистить их с помощью этого кода, процессы унаследовали бы системный PID 1 как родительский процесс и, возможно, стали бы зомби. - person Matt; 30.09.2016