Как полюбить systemd
Systemd — прародитель всех процессов, ответственный за поднятие Linux хоста.
Сегодня мы поговорим про systemd — подсистему управления службами в Linux, заменившую классический init и SystemV. И замена эта, надо сказать, достойная. Как и для большинства разработчиков, связанных с Linux, для меня init и SystemV — это, в первую очередь, запуск служб и загрузка системы, а уже потом — управление запущенными процессами.
Как и init, systemd — прародитель всех процессов, так сказать, демон инициализации демонов, ответственный за поднятие хоста в рабочее состояние.
Некоторые функции, реализуемые systemd, используются для управления системой, например, для монтирования файловых систем, управления устройствами, таймерами, а также запуска и управления системными службами для запуска системы.
В этой статье мы рассмотрим базовые функции systemd, которые используются как для запуска системы, так и после него.
Загрузка Linux
Хотя загрузка Linux – сложный и многоэтапный процесс, здесь нет никакой «магии». Перед тем как вдаваться в детали, предлагаю пройтись по процессам, которые происходят с момента включения машины до момента входа в систему.
Как правило, процесс загрузки воспринимают как нечто цельное, но это неправильно.
Загрузка состоит из, как минимум, трех разных этапов:
- загрузка аппаратной части: запуск «железа»;
- загрузка Linux: загрузка ядра, а затем, systemd;
- запуск рабочей среды: systemd подготавливает систему к работе.
Запуск Линукса начинается после того, как ядро запустило либо init, либо systemd — в зависимости от того, что используется в дистрибутиве. Демоны init и systemd запускают и управляют всеми другими процессами, поэтому их часто называют прародителем всех процессов.
Важно четко понимать различия между аппаратной загрузкой, загрузкой Linux и запуском рабочей среды. Если вы понимаете, где заканчивается один процесс и начинается другой, а также какую роль играет каждый из них в запуске системы до рабочего состояния, вы с легкостью найдете, в каком конкретно месте «загрузки» возникает проблема.
Запуск Linux — последний этап процесса загрузки. Именно он позволяет вывести систему в рабочее состояние, когда вы можете работать с ней. Запуск начинается тогда, когда ядро передает управление systemd.
Что не так с systemd
Systemd вызывает довольно противоречивые реакции у системных администраторов и технических специалистов. Тот факт, что systemd ответственен за такое большое число разных задач и процессов, привел к тому, что многие разработчики и системные администраторы высказываются резко против этого демона, отказываясь от его использования в пользу классических решений.
SystemV и systemd — это два разных метода запуска Линукса. Сценарии запуска SystemV и демона init — это старый метод. А юниты target в systemd — более современный. Хотя большинство современных дистрибутивов используют для запуска, завершения работы и управления процессами systemd, есть те, что это не делают. Одна из причин — некоторые создатели дистрибутивов и системные администраторы предпочитают старый SystemV.
Однако я считаю, что у обоих методов свои преимущества.
Чем хорош SystemV
SystemV более доступен. Запуск выполняется при помощи bash-скриптов. После того как ядро запускает init — скомпилированный бинарный файл — init запускает скрипт rc.sysinit, который выполняет множество задач для инициализации системы. После завершения rc.sysinit, init запускает /etc/rc.d/rc
, который, в свою очередь, запускает различные демоны, определенные сценариями запуска SystemV в /etc/rc.d/rcX.d
, где «X» — уровень выполнения (runlevel).
Кроме самого init, все эти скрипты и демоны — открыты и легко читаемы. Не составит никакого труда изучить эти скрипты и понять, как работает каждый из них и что конкретно происходит во время запуска системы. Однако я не думаю, что кто-то из системных администраторов часто этим занимается. Каждый запускаемый скрипт нумерован таким образом, чтобы запускать соответствующую службу в определенной последовательности. Службы запускаются последовательно и по одной за раз.
Systemd обязан своим появлением сотрудникам Red Hat — Леннарту Пёттерингу и Кэю Сиверсу. Фактически, это комплексная система больших, скомпилированных исполняемых файлов, логику которых не понять без доступа к исходному коду. Но поскольку systemd — open-source проект, проблем с «доступом к исходному коду» не возникает, просто это не очень удобно.
Однако своим появлением systemd значительно опровергает базовые принципы философии Linux. Как бинарный файл, systemd закрыт от прямого редактирования или просмотра системными администраторами. При этом он пытается «делать всё». Например, управлять запущенными службами. С другой стороны, он дает гораздо больше информации о состоянии, чем SystemV.
Systemd также управляет аппаратной частью, процессами и группами процессов, монтированием файловых систем и многим другим. Systemd присутствует практически в каждом аспекте современного Linux, что делает его универсальным инструментом управления системой. Всё это — нарушения главного принципа, который гласит, что все программы должны быть небольшими, а каждая программа должна делать что-то одно, но делать это хорошо.
Чем хорош systemd
Systemd параллельно запускает столько служб, сколько возможно, в зависимости от текущей стадии запуска системы. Естественно, это существенно ускоряет запуск. Времени от включения до экрана входа в систему тратиться гораздо меньше, чем в случае с SystemV.
Systemd управляет практически каждым аспектом работающей системы. Он может управлять запущенными службами, предоставляя значительно больше информации о состоянии, чем SystemV. Он также управляет аппаратной частью, процессами и группами процессов, монтированием файловых систем и многим другим (звучит знакомо, не правда ли?).
Инструментарий systemd — компилированные бинарные файлы, но набор инструментов открыт, потому что все конфигурационные файлы — это ASCII текст. Конфигурацию запуска можно менять через различные инструменты командной строки или GUI. Также можно менять или добавлять различные конфигурационные файлы, при необходимости.
Муки выбора
Зачем выбирать что-то одно, если можно работать с обеими подсистемами?
Я считаю, что причина всех противоречий между SystemV и systemd в том, что между ними нельзя выбирать на уровне системного администрирования. Выбор уже сделан за вас дистрибутивами и упаковщиками, но не без веских на то оснований: у замены init из-за его чрезмерно инвазивной природы, слишком много сложностей и последствий, с которыми было бы крайне сложно справиться вне создания дистрибутива.
Хотя в этом вопросе выбор уже сделан за меня, мои хосты в любом случае загружаются и работают, что все-таки, главное. Как конечный пользователь и системный администратор, мне нужно, чтобы я мог выполнять свои задачи, например, писать статьи вроде этой, устанавливать обновления, или писать скрипты, чтобы автоматизировать все, что можно и что нельзя. До тех пор, пока я могу выполнять всю работу, я не особо задумываюсь о порядке запуска, который вшит в моем дистрибутиве.
А вот о чем я думаю, так это об исправлении ошибок во время запуска или при управлении службами. Вне зависимости от используемой подсистемы, я знаю достаточно, чтобы восстановить последовательность действий при загрузке и отследить ошибки, исправив их.
Чем заменить SystemV
В прошлом уже предпринималось несколько попыток заменить SystemV чем-то более современным. Примерно два релиза подряд Fedora использовала Upstart, призванный заменить устаревающий SystemV, но Upstart не заменял init и не вносил значимых изменений в запуск. Поскольку Upstart практически не решал проблем SystemV, все усилия, связанные с его разработкой, были быстро заброшены в пользу systemd.
Несмотря на то что большинство разработчиков Linux согласны, что заменить устаревший SystemV – хорошая идея, именно за это systemd так не любят многие системные администраторы и разработчики. Вместо того чтобы пересказывать все так называемые проблемы, с которыми сталкиваются или сталкивались пользователи systemd, я лучше дам ссылку на две хороших, по моему мнению, статьи, которые ответят на все возможные вопросы по этой теме:
Линус Торвальдс, создатель ядра Линукса, кажется, не заинтересован в systemd. В 2014 году в статье ZDNet он четко высказался по этому поводу:
На самом деле, у меня нет какого-то особого мнения насчет systemd. Да, у меня были проблемы с некоторыми разработчиками, которые, как мне кажется, слишком легкомысленно относятся к ошибкам и совместимости и я думаю, некоторые решения просто безумны (например, мне не нравятся бинарные логи), но это все детали, а не фундаментальные проблемы.
Если вы вдруг не знаете манеры разговора Линуса, я напомню: если ему что-то не нравится, он очень откровенен, резок и прямолинеен в своих высказываниях. Можно сказать, его полюбили именно за его манеру высказываться о том, что ему не нравится.
В 2013 Пёттеринг написал пост в своем блоге, где развенчал мифы о systemd, попутно рассказав о цели его создания.
Задачи systemd
В зависимости от параметров, используемых при компиляции (о которых мы здесь не говорим) у systemd включает до 69 исполняемых файлов, которые выполняют, кроме прочего, следующие задачи:
- systemd запускается как PID 1 и выделяет запуску системы столько служб в параллельном режиме, сколько нужно. Это приводит к ускорению загрузки. Он также управляет последовательностью завершения работы.
- systemctl предоставляет пользовательский интерфейс для управления службами.
- Для обеспечения обратной совместимости предлагается поддержка SystemV и LSB.
- Управление службами и логами дает больше информации о состоянии служб, чем SystemV.
- Включает инструменты для базовой настройки системы, например: имя хоста, дата, язык, список авторизированных пользователей, запущенные контейнеры и виртуальные машины, системные учетные записи, рабочие директории и настройки, демоны для управления базовой настройкой сети, синхронизация сетевого времени, пересылка журналов и разрешение доменных имен.
- Управление сокетами.
- Таймеры systemd предоставляют расширенные cron-подобные возможности, включая запуски скриптов, привязанные ко времени от старта системы, запуск systemd, время последнего запуска таймера и многое другое.
- Инструментарий для анализа дат и времени, используемых в спецификациях таймеров.
- Монтирование и размонтирование файловых систем с иерархическим уведомлением обеспечивает более безопасное каскадирование.
- Позволяет создавать и управлять временными файлами, включая их удаление.
- Интерфейс с D-Bus позволяет запускать скрипты, когда устройства подключены или извлечены. Это позволяет рассматривать все устройства, подключаемые или нет, как plug-and-play, что сильно упрощает работу с ними.
- Инструмент для анализа последовательности загрузки позволяет найти службы, на запуск которых тратится больше всего времени.
- Создаёт журналы для хранения системных логов и включает инструменты для управления этими журналами.
Архитектура
Эти и другие задачи решаются различными демонами, управляющими программами и конфигурационными файлами. На рисунке показано, сколько компонентов входит в systemd. Это упрощенная, обзорная схема, показывающая основную архитектуру — в ней указаны не все файлы или службы. Кроме того, здесь нет никакой информации о потоке данных, который настолько сложный, что рассказывать о нем в контексте подобной обзорной статьи не имеет никакого смысла.
Если описывать все функции systemd, это заняло бы целую книгу. Но вам необязательно понимать, как компоненты systemd взаимодействуют друг с другом. Достаточно знать о компонентах и программах, управляющих различными службами Linux и позволяющих работать с логами и журналами. Но уже сейчас очевидно, что systemd это не какое-то монолитное чудовище, каким его считают некоторые критики.
systemd как PID 1
Systemd это PID 1. Некоторые функции, потенциал которых гораздо более обширный, чем в SystemV3 init, позволяют управлять многими аспектами Linux, включая монтирование файловых систем и запуск служб. Любых задач, не связанных с последовательностью запуска системы в этой статье мы не касаемся.
Итак, для начала, systemd монтирует файловую систему в /etc/fstab
, включая файлы подкачки (swap) или разделы. На данном этапе systemd получает доступ к конфигурационным файлам в /etc
, включая свой собственный. Для выбора загрузки он использует свою конфигурационную ссылку в /etc/systemd/system/default.target
.
default.target — это символичная ссылка на настоящий target. Для настольного ПК, это, как правило, graphical.target, что эквивалентно runlevel 5 в SystemV. Для серверных решений по умолчанию стоит multi-user.target, эквивалентный runlevel 3 в SystemV. emergency.target аналогичен однопользовательскому режиму. Target’ы и службы в systemd называются юнитами.
В таблице я сравниваю target systemd со старой системой запуска runlevel в SystemV. systemd предоставляет target псевдонимы (алиасы) для обеспечения обратной совместимости. Алиасы позволяют скриптам — и системным администаторам — использовать команды SystemV, как init 3 для смены runlevel. Естественно, команды SystemV передаются в systemd для интерпретации и выполнения.
В конфигурационных файлах каждого target расписан набор зависимостей. Systemd запускает требуемые службы для запуска хоста на определенном уровне функциональности. Когда все зависимые объекты запущены, система работает на соответствующем уровне target. В таблице юниты с максимальной функциональностью указаны в верхних строках, к последним строкам их функциональность снижается.Кто такой DevOps и как им стать: план обученияtproger.ru
Systemd также просматривает старые каталоги SystemV init для поиска каких-либо файлов запуска. И если подсистема их находит, она использует их в качестве конфигурационных файлов для запуска служб, описанных этими файлами. Устаревшая сетевая служба –— хороший пример той, что все еще использует файлы запуска SystemV в Fedora.
Схема 3 скопирована со страницы описания процесса загрузки проекта man-pages. В ней указана общая последовательность событий во время запуска system и основные требования по порядку загрузки.
Юниты sysinit.target и basic.target считаются контрольными точками в процессе запуска. Хотя одна из главных целей systemd — параллельный запуск служб, некоторые демоны и юниты должны запускаться первыми. Такие контрольные точки нельзя пропустить до тех пор, пока все необходимые службы и юниты, установленные в рамках этой контрольной точки, не будут запущены.
Sysinit.target завершается, когда все юниты, от которых он зависит, выполнены. Все эти юниты, монтирование файловой системы, настройка файла подкачки, запуск udev, установка генератора случайных чисел, инициализация низкоуровневых служб и настройка криптографических служб (если одна или несколько файловых систем зашифрованы) должны быть завершены для выполнения sysinit.target. А внутри самого sysinit.target, все процессы могут выполняться параллельно.
Юнит sysinit.target запускает все низкоуровневые службы и юниты, необходимые для достижения системой минимальной функциональности. Без их загрузки система не может перейти к basic.target.
После выполнения sysinit.target, systemd запускает все требуемые для нового target юниты. Basic.target обеспечивает дополнительную функциональность, запуская юниты, которые нужны для всех остальных target’ов. Сюда входят такие вещи, как установка путей к рабочим директориям, сокеты и таймеры.
Наконец, инициализируются target пользовательского уровня: multi-user.target или graphical.target. multi-user.target должен быть выполнен до того, как будут достигнуты зависимости graphical.target. Указанные на схеме 3 target’ы — это обычные юниты запуска. Как только один из них выполнен, запуск завершен. Если по умолчанию установлен multi-user.target, вы попадете на текстовый вариант логина в консоли. Если установлен graphical.target вы увидите графический интерфейс входа в систему; конкретный интерфейс логина GUI, который вы видите, зависит от настроек.
В мануале man-pages подробно описана последовательность и карта загрузки на начальный RAM диск (initrd), а также процесс завершения работы systemd.
В systemd также есть инструмент для вывода зависимостей всей загрузки целиком или конкретного юнита. Юнит — это контролируемый systemd блок, который может быть как каким-то конкретным демоном, например, httpd или sshd, так и таймером, монтированием, сокетом или чем-то другим. Попробуйте, введите следующую команду и посмотрите на результат:
systemctl list-dependencies graphical.target
Обратите внимание, что это команда полностью раскрывает юниты верхнего уровня, необходимые для запуска системы в GUI. Используйте — all, чтобы развернуть все остальные юниты.
systemctl list-dependencies --all graphical.target
Вы можете искать строки, например, «target,» «slice,» и «socket», используя инструменты поиска команды less. Теперь попробуйте.
systemctl list-dependencies multi-user.target
и
systemctl list-dependencies rescue.target
и
systemctl list-dependencies local-fs.target
и
systemctl list-dependencies dbus.service
Этот инструмент помогает мне визуализировать специфику зависимостей запуска хоста, на котором я работаю. Попробуйте немного изучить древо запуска для одного или нескольких ваших Linux хостов. Но будьте осторожны: как написано в руководстве man-page:
Обратите внимание, эта команда лишь выводит юниты, загруженные в текущий момент в память менеджером служб. В частности, эта команда не подходит для получения полного списка всех обратных зависимостей конкретного юнита, поскольку она не покажет зависимостей незагруженных юнитов.
Пост скриптум
Даже касаясь systemd лишь поверхностно, очевидно, что это мощный, но сложный инструмент. Также очевидно, что systemd не является монолитным, огромным или непонятным исполняемым файлом. Скорее, это большое число небольших компонентов и подкоманд, созданных для выполнения конкретных задач.
В следующей статье мы детально коснемся загрузки systemd, конфигурационных файлов, смены target по умолчанию, а также поговорим о том, как создать простой юнит.