Заметки об ОС Linux. Часть 3. Система инициализации
Как было сказано ранее, /sbin/init
— это программа, которая стартует первой в системе (в пользовательском режиме). Обычно имеет PID=1. Главная задача системы инициализации (далее — СИ) — довести систему до состояния, пригодного для использования. Для этого СИ может монтировать какие-либо разделы и файловые системы (так например на определённом этапе загрузки СИ выполняет монтирование ряда ФС), а также запускать установленные в системе демоны и иные программы. Основные параметры загрузки содержатся в файле /etc/inittab
.
В некоторых СИ используются уровни выполнения — определённые стадии загрузки системы, на которых пользователю доступны какие-либо её возможности.
Помимо загрузки ОС, СИ заботится и о её выключении, завершая все сервисы и размонтируя файловые системы, после чего вызывая системный вызов для отключения ПК.
Реализации init'ов
Простейшие СИ
По умолчанию ядро после своей инициализации запускает программу /sbin/init
и паникует, если не нашло её. Однако данное поведение можно и изменить, передав параметр init=/путь/до/СИ
. Например, в качестве инита вы можете использовать вашу командную оболочку:
init=/bin/ash
Тогда первым процессом будет запущена оболочка ash
из состава BusyBox. Однако помните, что в задачи системы инициализации входит подготовка ОС к дальнейшему функционированию: монтирование различных файловых систем (в т.ч. всяких /dev/
, /proc/
, /sys/
), запуск демонов и иных программ. Если вместо обычной системы инициализации или программы, её заменяющей, вы запустите командную оболочку, то ничего из этого выполнено не будет — у вас просто запустится shell. Вы получите как бы рабочую систему с правами root
, но не более того. Не будут работать логирование, графика, сеть и куча других вещей, которые запускает СИ.
Идя по пути усложнения вещей, мы можем написать shell-скрипт, который выполняет какие-то самые базовые вещи по настройке и запуску ОС. Например:
#!/bin/ash
export PATH=/bin:/sbin
# Монтируем всякие разные файловые системы
mount proc /proc -t proc
mkdir -p /dev/pts
mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts
mount -t tmpfs none -o nodev,nosuid,noatime /tmp
mount -t tmpfs none -o nodev,nosuid,noatime /var/log
mount -t tmpfs none -o nodev,nosuid,noatime /var/run
mount -t tmpfs none -o nodev,nosuid,noatime /run
mount sysfs /sys -t sysfs
# Запускаем системный логгер
syslog
klogd -c 3
# Инициализация одного TTY
getty tty1 # Управление передаётся процессу `/sbin/getty`
# Когда мы завершим процесс `getty`, можно считать,
# что мы выключаем систему. Поэтому нам нужны
# действия по завершению её работы:
# Завершаем запущенные в скрипте сервисы
killall klogd
killall syslog
# Убиваем всё остальное
kill -TERM -1
kill -KILL -1
# Размонтируем все ФС
umount -a
exit
SysVInit
Ранее SysVInit был де-факто стандартом в дистрибутивах Linux, но в 2010-х были относительно успешные попытки заменить его на другие СИ.
Достоинства:
- Устоявшаяся и хорошо понятная классическая система;
- Простой процесс настройки;
- Нетребовательность к ресурсам компьютера;
- Следование философии UNIX;
Недостатки:
- Неудобная работа с сервисами;
- Каждый сервис — это обычный shell-скрипт;
- Отсутствие параллельного запуска загрузочных скриптов, из-за чего хотя бы один «зависший» скрипт застопорит загрузку/выключение системы;
Для SysVInit требуются загрузочные скрипты. С примером таких скриптов вы можете ознакомиться в руководстве LFS.
OpenRC
OpenRC — система инициализации с поддержкой зависимостей. Запускает необходимые системные сервисы в определённом порядке при загрузке, управляет ими во время работы системы и останавливает их при завершении работы. Имеет возможность параллельного запуска процессов для сокращения времени загрузки.
runit
runit — кроссплатформенная система инициализации для систем семейства UNIX, позиционирующая себя как замена SysVInit и других СИ. Как и другие системы инициализации, запускается первым процессом в системе. Работа runit состоит из трёх этапов:
- runit запускает
/etc/runit/1
и ждёт, пока он завершится. - Запускает
/etc/runit/2
, который не должен завершаться до тех пор, пока система не остановится или не перезагрузится. В случае сбоя/etc/runit/2
перезапускается. На этом этапе он также опционально может обрабатывать сигналINT
(нажатие Ctrl+Alt+Del на клавиатуре). - Если
runit
было сказано остановить или перезагрузить систему, либо если этап №2 завершился без ошибок, то запускается/etc/runit/3
, который выполняет задачи по выключению, остановке или перезагрузке.
runit предоставляет следующие возможности:
- демонизация процессов;
- журналирование вывода процессов;
- запуск, остановка, перезапуск сервисов;
- выключение или запуск сервисов автоматически по мере их появления или удаления из списка;
- и т.д.
systemd
systemd — более крупная и сложная программа, чем все остальные, которые здесь описаны. Представляет собой менеджер системы и служб, который выполняется как самый первый процесс в системе и запускает остальные её компоненты. Параллельно запускает сервисы, а также имеет поддержку зависимостей у этих сервисов.
Поддерживает сценарии SysVInit, да собственно и является заменой последнего.
Среди прочих его функций можно отметить программу journalctl
для журналирования системы, утилиты управления базовой конфигурацией системы (установка имени хоста, настройка даты и времени, etc.), ведение списка вошедших в систему пользователей, системных учётных записей, запущенных контейнеров, виртуальных машин, т.д.
systemd использует юниты — конфигурационные файлы, синтаксис которых напоминает формат *.ini
, которые содержат в себе команды для монтирования файловых систем, запуска системных компонентов, включения подкачки и т.д.:
- сервисы (
*.service
); - точки монтирования файловых систем (
*.mount
); - устройства (
*.device
); - сокеты (
*.socket
); - etc.
Некоторым людям не особо нравится systemd за его монолитность (хотя в системах Linux куча других монолитных компонентов, то же ядро например) и то, что он пытается заменить собой кучу других компонентов системы, а не только /sbin/init
.
Сравнение систем инициализации
Таблица взята из Gentoo WiKi.
Характеристика | SysVInit | OpenRC | runit | systemd |
---|---|---|---|---|
Поддерживаемые платформы | Linux/BSD | Linux/BSD | Linux/BSD/Darwin | Linux |
Основной язык программирования | C | POSIX Shell + C | C | C |
Основные зависимости | — | init (SysVInit или BSD) | — | D-Bus |
Формат скрипта/сервиса | Один скрипт (который может запускать несколько других) | Shell-скрипты | Shell-скрипты | Конфиг ini |
Конфигурация для каждого сервиса | Нет | Есть | Нет | Есть |
Параллельная загрузка сервисов | Нет | Есть (опционально) | Есть (???) | Есть |