Catatonit

Материал из ALT Linux Wiki

Catatonit представляет собой программу /sbin/init для использования в контейнерах.

Он позволяет решать проблему PID 1 zombie reaping problem.

По сути, catatonit - это переписанный initrs (Rust) на C, который в свою очередь является переосмыслением других контейнерных init-систем, таких как tini и dumb-init.

Суть проблемы PID 1 zombie reaping problem [1]

Все процессы в Unix представлены в виде дерева. Каждый процесс порождает дочерние процессы, и каждый процесс имеет родителя кроме самого верхнего (или корневого).

Корневой процесс это init. Он запускается ядром при загрузке системы. init отвечает за старт остальных частей системы, например, демона SSH, демона docker, запуск Apache/Nginx, запуск графического интерфейса и так далее. Каждый из них в свою очередь запускает свои дочерние процессы.

Unix сделан таким образом, что родительский процесс ждет завершения дочернего чтобы получить код завершения (exit status). Зомби процесс существует до тех пор, пока родительский процесс не закончит это действие, используя семейство системных вызовов waitpid(). Т.е. зомби-процессы - это процессы, которые завершились, но их родительские процессы еще ждут их завершения.

Но есть особый случай. Когда родительский процесс завершился, намеренно или из-за действия пользователя. Тогда у дочерних процессов больше нет родителя, поэтому они становятся “сиротами” (это технический термин).

Тут в игру вступает процесс init. У процесса init – PID 1 – есть специальная задача: “усыновлять” осиротевшие процессы (это снова настоящий технический термин). Это означает, что init становится родителем таких процессов, не смотря на то, что они в реальности не были порождены init’ом.

Ядро ОС ожидает от init специального поведения: ядро считает, что init должен обрабатывать (собирать, “reap”) усыновленные процессы тоже.

Каждый раз когда процесс, имеющий детей, завершается, он ожидает, что init подчистит все за ним. Это описано детально в двух очень хороших книгах: Operating System Concepts и Advanced Programming in the UNIX Environment.

Особенности docker

Ядро ОС завершает весь контейнер со всеми процессами внутри. Эти процессы завершаются с помощью SIGKILL. Поэтому нет способа завершить эти процессы чисто. Допустим, ваше приложение пишет что-то в файл. Файл может быть поврежден если приложение завершилось таким образом во время записи. Нечистое завершение процессов это плохо. Это почти как выдернуть шнур питания у сервера.

Но почему нас должно волновать, что процесс init завершается сигналом SIGTERM? Потому что docker stop посылает SIGTERM процессу init. “docker stop” должен остановить контейнер правильно, чтобы его можно было потом запустить с помощью “docker start”. [1]

Как работает catatonit

Если catatonit запущен с PID = 1, то Catatonit становится корневым процессом.

И в случае, когда процесс становится зомби или сиротой, Catatonit знает как правильное его завершить. Он пересылает (почти) все сигналы порожденному процессу, завершает контейнер, когда дочерние процессы завершены, и в противном случае очищает другие завершённые процессы (зомби).

В отличие от других контейнерных систем инициализации (таких как "tini" или "dumb-init"), которые используют sigwait(2), catatonit использует современные средства Linux (такие как signalfd(2)) и не имеет никаких дополнительных функций.

Использование Catatonit используется также как и docker-init-системы. Он принимает команды и список аргументов для этой команды. Если catatonit не является pid1, он попытается использовать поддержку sub-reaper в ядре. Если необходимо, чтобы сигналы пересылались всей группе процессов порожденного процесса, необходимо указывать -g (в противном случае сигналы просто пересылаются порожденному процессу).

Установка Catatonit использует autotools для сборки, поэтому собирается и устанавливается стандартным образом:

% ./autogen.sh
% ./configure
% make
% sudo make install

Лицензия

GNU General Public License 3 и выше.