Данный конспект был основан на записи лекции №9 (*тык*) с канала А. В. Маятина
Система инициализации init из UNIX System V в своей архитектуре имела недостаток: скрипты установленного уровня выполнения исполнялись последовательно единожды непосредственно после загрузки ОС. Из-за этого:
В 2006 году компания Canonical, которая поддерживает дистрибутив Ubuntu, разработала замену - систему Upstart
Upstart был основан на событиях, которые заменили уровни исполнения. Такими событиями были:
Такой асинхронный подход позволяет сервисам запускаться параллельно, если это возможно. Помимо этого Upstart был обратно совместимым с SysV init, что позволяло легко мигрировать на Upstart
Upstart стал системой инициализации в Ubuntu в 2006, в Fedora и Red Hat Enterprise Linux в 2010
Сама же система Upstart работает так: есть список заданий (job), которые как правило либо сервисы, либо краткосрочные задачи. Само описание заданий хранится в конфигурационных файлах /etc/init/<задание>.conf. Upstart постоянно отслеживает изменения в этих файлах
init (из /sbin/init) читает все описания заданий из /etc/init/stop и состоянии waiting и ждет наступления указанного в нем событияstart, и оно последовательно проходит стадии: starting -> pre-start -> spawned -> post-start -> runningstop, и задание переходит в цепочку состояний: pre-stop -> stopping -> killed -> post-stop -> waitingСамо описание может выглядеть так:
# Описание сервиса
description "Мой сервис"
# Условия запуска: когда система переходит на "обычный" уровень
# и когда сетевые интерфейсы подняты
start on (runlevel [23] and net-device-up IFACE=eth0)
# Условия остановки: когда система выключается или перезагружается
stop on runlevel [!23]
# Команда, выполняемая при запуске сервиса
exec /usr/bin/my-server
# Перезапуск при падении
respawn
Несмотря на это, Upstart имел много недостатков:
ptrace для отслеживания состояния процессов, но этот метод конфликтовал с другими инструментами и считался небезопаснымВ 2010 появилась система инициализации systemd. Далее с 2015 года systemd поставлялась во всех дистрибутивах, заменив Upstart и SysV init. Это привело к прекращению разработки Upstart в сентябре 2014 года
В конце 2009 года инженеры Леннарт Пёттеринг и Кей Зиверс из компании Red Hat сформулировали основные принципы будущей системы, которая бы заменила SysV init и Upstart. Тогда архитектор Леннарт Пёттеринг заметил, что:
Как правило, процессы общаются через сокеты, и общаются они не сразу же после создания. Тогда, если сервис A зависит от сервиса B, можно сразу запускать сервис B. По мере того, как сервис A начнет что-то писать в сокет, новая система может передать уже открытый сокет сервису, который ещё не запущен, чтобы тот начал обрабатывать поступившие соединения
Такой подход ускоряет загрузку и упрощает перезапуск зависимых служб, но существует риск того, что при сбое потеряются важные данные
Монтирование файловых систем происходит непосредственно после запуска ОС, однако сама файловая система используется через некоторое время
Тогда запросы к файловой системе можно забуферизовать, подключить файловую систему и выполнить их в тот момент, когда файловая система готова
Классический init при запуске обычной системы много раз задействовал тяжеловесные утилиты, а именно: 77 раз grep, 92 раза awk, 74 раза sed, 23 раза cat и так далее
В половине случаев возможности этих утилит были избыточны для их применения, но в память загружался и выгружался весь код утилит
Поэтому приняли решение вместо них использовать готовые функции на C
Все эти недочеты были учтены в новой системе - systemd
Также systemd заменила уровни выполнения на цели. Цели представляли целевые состояния ОС, такие как многопользовательский режим или режим с графической подсистемой
Вместо заданий в systemd появились юниты. Юниты описывались текстовыми файлами в каталоге /usr/lib/systemd/system/, а расширение указывало на тип юнита:
.service - сервис, который запускает демон.socket - сокет, к которому можно было настроить свой обработчик.device - устройство, к которому можно было настроить свой обработчик.mount - точка монтирования при загрузке ОС.automount - точка монтирования по требованию (загружается при первой обращении).target - цель. Помимо этого systemd позволяет строить иерархию целей из зависимостей, например, можно сделать так, чтобы переход в графический режим был невозможен без перехода в многопользовательский режим.timer - таймерВнутри текстовый файл содержит ее описание. Например, простой сервис может выглядеть так:
[Unit]
Description=My Application
After=network.target # нужна цель `network`
[Service]
User=myappuser # запустить от имени myappuser
ExecStart=/usr/bin/myapp # исполняемый файл
Restart=on-failure # перезапустить при падении
StandardOutput=journal # записывать логи в журнал systemd
В секции [Unit] указывались зависимости сервиса:
Requires - жесткая зависимость, если зависимость не запустилась, текущий юнит тоже не запуститсяWants - мягкая зависимость, неудача запуска юнита не повлияет на состояние текущегоRequisite - проверка состояния, если указанный юнит не активен, то текущий юнит не запускаетсяConflicts - останавливает указанный юнит, если он запущен, и не позволяет работать параллельноAfter - запускает текущий юнит после указанногоBefore - запускает текущий юнит до указанногоВ секции [Install] можно указать обратные зависимости:
WantedBy - обратный WantsRequiredBy - обратный RequiresПри загрузке systemd читает конфигурацию, монтирует файловые системы, поднимает сеть, запускает системные службы и доводит систему до нужного целевого состояния, например до multi-user.target (многопользовательский режим) или graphical.target (режим с графической оболочкой)
Также systemd предоставляет инструменты для управления юнитами
systemctl start my-service запускает сервис my-service.servicesystemctl stop my-service останавливает сервисsystemctl enable my-service включает автозапуск, но не запускает сервисsystemctl disable my-service отключает автозапускsystemctl set-default my-target устанавливает цель (по сути эта команда делает символическую ссылку /etc/systemd/system/default.target на /usr/lib/systemd/system/my-target.target)
Текущую цель можно посмотреть через systemctl get-default
systemctl status my-service - посмотреть состояние сервиса и последние логиsystemctl restart my-service - перезапустить сервисjournalctl -u my-service - посмотреть логи конкретного сервиса (journalctl -f - слежка в реальном времени)Кроме этого вместо привычного названия процесса init появилось /usr/lib/systemd/systemd, что критиковалось многими консерваторами
Но у systemd есть недостатки:
Тем не менее сейчас почти все популярные дистрибутивы используют systemd
Помимо популярного systemd немногие дистрибутивы используют менее громоздкие решения
runit
runit была создана для замены SysV init как легковесная и кроссплатформенная система. runit придерживается философии Unix “программа должна делать что-то одно, но делать это хорошо” и занимается исключительно инициализацией системы и контролем за сервисами, не беря на себя другие функции, как это делает systemd
Каждый сервис в runit - это просто папка с файлом run, который запускает процесс в фоне
runit очень быстрая и экономичная система, что делает её популярной в контейнерах и встраиваемых системах
OpenRC
OpenRC была создана разработчиками Gentoo для замены набора скриптов инициализации этого дистрибутива, но сейчас доступна и в других системах
В отличие от SysV init, OpenRC понимает зависимости между сервисами и, где возможно, запускает их параллельно, ускоряя загрузку
OpenRC не заменяет init целиком, а работает поверх него, что позволяет ей быть очень гибкой и не требовать кардинальной перестройки системы.
launchd
Система launchd была создана компанией Apple в 2005 году для Mac OS X 10.4 Tiger. До версии 10.4 операционная система Mac OS X (которая является ответвлением от ОС BSD) использовала SysV init
Процессы в launchd могут быть запущены только тогда, когда они действительно нужны - то, что потом переняла система systemd
Конфигурация каждого сервиса в launchd хранится в простых XML-файлах формата .plist. Для работы с launchd используется команда launchctl
В 2006 году дистрибутив Ubuntu Linux рассматривался с использованием системы launchd, но тогда такое решение было отклонено, так как launchd лицензировалась под Apple Public Source License, что могло создать проблемы. Сейчас же launchd лицензируется под проприетарной лицензией