Автор оригинала: Леннарт Поттеринг (Lennart Poettering).
Ссылка: http://0pointer.de/blog/projects/systemd-for-admins-3.html.
Дата: 01.10.2010.
Как я могу сконвертировать скрипты инициализации SysV в файлы служб systemd?
Unix и Linux службы (демоны) традиционно запускались через SysV скрипты инициализации (англ. SysV init scripts). Это Bourne Shell скрипты, обычно размещенные в директории вроде /etc/rc.d/init.d/ и вызывающиеся с одним из стандартизированных аргументов (слов) таких как start, stop или restart для запуска, остановки или рестарта службы соответственно. Для запуска они обычно содержат вызов бинарного файла демона, который затем форкает фоновый процесс. Shell-скрипты, как правило, бывают медленными, трудно читаемыми, слишком многословными и хрупкими. Хотя они и очень гибкие (в конце концов, это просто код), но некоторые вещи довольно сложно сделать с shell-скриптами (например, параллельное исполнение, правильный контроль процессов, а также простую настройку контекстов выполнения). systemd обеспечивает совместимость с этими скриптами, но из-за указанных недостатков рекомендуется использовать родные файлы служб systemd для всех установленных демонов. Также, в отличие от скриптов SysV, которые должны быть скорректированы для каждого дистрибутива, файлы служб systemd совместимы со всеми дистрибутивами, в которых работает systemd (а таких становится все больше и больше...). Ниже приводится краткое руководство, поясняющее как на основе SysV скрипта инициализации получить родной файл службы systemd. В идеале, проекты в апстриме должны включать файлы службы systemd в свои архивы. Если вы успешно сконвертировали SysV скрипт, в соответствии с инструкциями, то было бы хорошей идеей отправить файл как патч в апстрим. Как подготовить патч будет обсуждаться в более поздней статье. Достаточно сказать в данный момент, что man страница daemon(7) содержит много полезной информации по этому вопросу.Что ж, начнем. Для примера, сконвертируем init-скрипт демона ABRT в файл службы systemd. ABRT (Automatic Bug Reporting Tool) - это, как видно из расшифровки, служба для формирования аварийных дампов. ABRT является стандартным компонентом Fedora. SysV скрипт доступен здесь.
На первом шаге при преобразовании такого скрипта необходимо его прочитать (да ладно?!) и извлечь полезную информацию из, как правило, довольно длинного сценария. Почти во всех случаях скрипт состоит в основном из шаблонного кода, который совпадает, или по крайней мере, очень похож во всех init скриптах. И обычно такой код просто копируется и вставляется из одного скрипта в другие. Итак, давайте извлечем интересную информацию из нашего скрипта:
- Описание службы: "Daemon to detect crashing apps". Как оказалось, скрипт включает множество строк комментариев, которые явно избыточны и относятся к самому скрипту. Файлы служб systemd также включают в себя описание, но только самой службы, а не файла для ее запуска.
- LSB заголовок [1] содержит информацию о зависимостях. Т.к. systemd построен вокруг основанной на сокетах активации, то обычно не требуется ручная настройка зависимостей (подробнее об сокет активации см. в статье-анонсе). В этом случае ценна только информация о зависимости от $syslog (это означает, что abrtd требует syslog). В тоже время, зависимость от $local_fs является избыточной, т.к. systemd всегда запускает службы уже после того, как все локальные файловые системы готовы.
- LSB заголовок показывает, что эта служба должна быть запущена в 3-ем (multi-user) и 5-ом (графический) уровне запуска (runlevel).
- Путь к бинарнику демона: /usr/sbin/abrtd
И вот, что уже имеем. Все оставшееся содержимое этого 115-строчного shell скрипта просто шаблонный или избыточный код: код, который занимается синхронизаций и сериализацией при запуске (код относительно блокировки файлов), или выводом сообщений о состоянии (код, с вызовами echo), или просто разбором слов (большой блок case).
Из полученной информации теперь мы можем написать наш файл службы systemd:
[Unit]Немного поясним содержимое файла. Секция [Unit] содержит общую информацию о сервисе. systemd управляет не только системными службами, но также и устройствами, точками монтирования, таймерами и другими компонентами системы. Юнит (unit) - это общий термин для всех объектов systemd, поэтому секция [Unit] включает информацию, которая может быть применима не только к службам, но и к другим поддерживаемым типам юнитов. В нашем случае мы установили следующие настройки юнита. Мы определили строку с описанием и установили, что этот демон будет запускаться после Syslog[2] (подобно тому, как это было сделано в LSB заголовах исходного init-скрипта). Для создания зависимости от Syslog мы добавили после "After=" строку "syslog.target". Последняя представляет собой специальный юнит в systemd, а также является стандартизированным именем для записи в журнал. Для получения подробной информации о таких стандартных именах смотрите systemd.special(7). Отметим, что зависимость типа After= только кодирует предпологаемый порядок, но, в действительности, не служит причиной запуска syslog, когда запущен abrtd - и это вполне то, что мы хотим. ABRT на самом деле отлично работает даже без syslog. Однако, если они оба запущены (так обычно и бывает), то порядок их старта управляется этой зависимостью.
Description=Daemon to detect crashing apps
After=syslog.target
[Service]
ExecStart=/usr/sbin/abrtd
Type=forking
[Install]
WantedBy=multi-user.target
Следующая секция это [Service], которая содержит информацию о самой службе. Включает все параметры, которые применимы только к службе, и не применимы к другим типам юнитов (точкам монтирования, устройствам, таймерам, ...). Здесь используются две установки: "ExecStart=" задает путь к бинарному файлу, запускаемому при старте службы. А воспользовавшись параметром "Type=" мы объяснили systemd то, как служба сообщит о завершении процесса запуска. Поскольку традиционные Unix демоны делают это, возвращая в родительский процесс после форка и запуска в фоне демона, мы установили здесь тип в "forking". Что говорит systemd ждать, пока запущенный бинарник завершится, а затем рассмотреть еще работающие процессы, потом процессов демона.
Последняя секция это [Install]. Она содержит информацию о том, как должна выглядеть предложенная установка, т.е. при каких обстоятельствах и каким триггером служба должна быть запущена. В данном случае мы просто скажем, что эта служба будет запущена, когда активируется юнит multi-user.target. Это специальный юнит (см. выше), роль которого в основном аналогична классическому SysV Runlevel 3[3]. Настройка WantedBy= мало влияет на демон во время выполнения. Ее читают только при выполнении команды systemctl enable, которая является рекомендуемым способом для включения службы в systemd. Эта команда просто убедится, что наша маленькая служба автоматически запустится при запросе multi-user.target (что происходит при нормальной загрузке [4]).
Вот и все. Сейчас у нас уже есть минимальный рабочий файл службы systemd. Для тестирования мы скопируем его в /etc/systemd/system/abrtd.service и вызовем systemctl для перезагрузки демона. Это нужно, чтобы systemd подхватил файл и запустил службу с ним: systemctl start abrtd.service. Мы можем проверить состояние службы через systemctl status abrtd.service. А также мы можем остановить ее, воспользовавшись командой systemctl stop abrtd.service. Наконец, мы может активировать ее при каждой загрузке через systemctl enable abrtd.service.
Файл службы, приведенный выше, конечно достаточный, но его можно еще слегка улучшить. Немного обновленный вариант:
[Unit]Что мы изменили? Всего две вещи: мы немного улучшили строку описания. Однако, более важно то, что мы изменили тип службы на dbus и указали имя шины D-Bus. Почему мы это сделали? Как уже упоминалось, классические SysV службы демонизируются (англ. daemonize) после старта, обычно дважды форкаясь и отвязываясь от всех терминалов. Хотя, это полезно и необходимо, когда демоны запускаются с помощью сценария, но в этом нет необходимости (и медленно), а также контрпродуктивно при условии использования процесса-няни (например, systemd). Причина в том, что отделившийся процесс демона, как правило, имеет мало общего с оригинальным процессом, запущенным systemd (собственно цель демонизации - снять эту связь). Это создает трудности для systemd в выяснении того, какой из процессов после форка является основным, а какой лишь вспомогательным. Эта информация является критически важной для реализации "няни", т.е. наблюдения за процессом, автоматического рестарта при падении, сбора информации о кодах выхода и т.п. Для того, чтобы systemd было проще узнавать главный процесс демона, мы изменили вид службы на dbus. Этот тип пригоден для всех служб, которые получают имя по системной шине D-Bus на последнем шаге своего запуска (initialization[5]). ABRT - это одна из них. Благодаря этой установке systemd будет порождать процесс ABRT, который больше не будет форкаться (это настраивается через -d -s параметры демона), и systemd будет рассматривать службу полностью запущенной, как только com.redhat.abrt появляется на шине. Таким образом, процесс, порожденный systemd, теперь является основным процессом демона, а также systemd получил надежный способ выяснить, когда же демон полностью загрузился, плюс теперь может легко контролировать его.
Description=ABRT Automated Bug Reporting Tool
After=syslog.target
[Service]
Type=dbus
BusName=com.redhat.abrt
ExecStart=/usr/sbin/abrtd -d -s
[Install]
WantedBy=multi-user.target
И это все, что в нем есть. Мы имеем простой файл службы systemd, который содержит в 10 строках больше информации, чем оригинальный SysV-скрипт в 115. И даже сейчас его можно усовершенствовать, используя дополнительные функции systemd. Например, мы могли бы установить Restart=restart-always для того, чтобы systemd автоматически перезапускал службу при ее падении. Также мы могли бы использовать OOMScoreAdjust=-500 чтобы попросить ядро не убивать процесс при нехватке памяти. Или мы могли бы использовать CPUSchedulingPolicy=idle для того, чтобы процессы abrtd выполнялись только во время бездействия системы.
Для получения дополнительной информации о вариантах конфигурации, упомянутых здесь, смотрите соответствующие man-страницы systemd.unit(5), systemd.service(5), systemd.exec(5). Или читайте все man-страницы, относящиеся к systemd.
Конечно, не все SysV скрипты также легко конвертировать как этот, но, к счастью, подавляющее большинство.
На сегодня все. Встретимся в следующей части!
Примечания
[1] LSB заголовок является соглашением о включаемых в блок комментариев в начале SysV скрипта мета данных о службе. Определено оно в Linux Standard Base. Оно было предназначено для стандартизации скриптов инициализации между дистрибутивами. Хотя большинство дистрибутивов приняло эту схему, обработка заголовков значительно различается в разных дистрибутивах. Это до сих под делает необходимым корректировку скриптов для каждого дистрибутива. Т.е. LSB спецификация не выполнила своего предназначения.
[2] Строго говоря, эта зависимость также излишня в системе где демон Syslog может активироваться через сокет. Современные системы syslog (например, rsyslog v5) включают патчи для возможности такой активации. Если используется такая система, то настройка After=syslog.target является избыточной и ненужной. Однако, для сохранения совместимости со службами syslog, которые не были обновлены, мы оставим эту зависимость.
[3] По крайней мере так это было определено в Fedora.
[4] Обратите внимание, что в systemd загрузка в графическом режиме (graphical.target, играющая роль SysV runlevel 5) является надстройкой над загрузки в консольном режиме (multi-user.target, т.е. как 3-й runlevel). Это означает, что настроенная на запуск в графическом режиме служба также будет стартовать и консольном режиме.
[5] На самомм деле большинство служб в Fedora настроена таким образом, чтобы они получали имя с системной шины после запуска.