Russian Fedora

cообщество русскоязычных участников
международного проекта Fedora

systemd с точки зрения мэйнтейнера upstream-проекта

Это архивная статья

Теперь уже самым закоренелым скептикам должно быть понятно, что systemd, это нынешний стандарт. Для закрепления успеха systemd продвигают в LSB с начала 2012 года.
Однако, несмотря на огромнейшую гору документации по systemd (и даже на русском), спрос на нее все еще заметен.
Инженеh SUSE, Neil Brown написал пару статей (часть 1 и часть 2), где попытался описать свой опыт с systemd, как upstream-мэйнтейнера mdadm и nfs-utils.
Для начала Neil отмечает, что init-скрипты слишком сильно отличаются от дистрибутива к дистрибутиву, чтоб имело смысл их поставлять в составе файлов в upstream. Да и для сложных случаев, таких, как nfs-utils, синхронизация с помощью SysV была недостаточной, и Neil затрудняется вспомнить, есть ли дистрибутив, в котором демоны NFS для сложных конфигураций были бы запущены в нужном порядке. А вот в случае с systemd, это стало возможным - и общая настройка для всех дистров, и точный порядок запуска.
Neil увидел уменьшение объема скриптов systemd по сравнению с SysV (примерно с 800 строк до менее 200 строк), зато ему пришлось включить большее количество описаний сервисов - вместо двух SysV-скриптов, для nfs-utils понадобилось 14 systemd-файлов. К счастью среди этих 14 файлов присутствуют 4 *.target (в терминологии systemd, это некая "точка" на дереве загрузки системы, достигнутая стадия), что упрощает жизнь пользователей.
Дальше Neil заинтересовался, как бы не дать повода пользователю редактировать unit-файлы, одновременно позволив ему изменять ряд параметров (количество потоков демона и т.п.). Тут Neil увидел область, нуждающуюся доработки. Например, если пользователь хочет переназначить порт, то было бы логично просто установить переменную $MOUNTD_PORT где-нибудь в /etc/sysconfig/ или /etc/defaults/. Однако, тогда демону может потребоваться ключ командной строки, который не нужен, если порт не переназначается. Т.е. требуется написать что-то типа
/usr/sbin/rpc.mountd ${MOUNTD_PORT:+-p $MOUNTD_PORT}
(если установлена переменная, то добавить ключ командной строки, иначе не добавлять). В systemd возможности задавать такие условия нет, и пользователю придется пересоздавать unit-файл в /etc/systemd. А это "перезапишет" изменения в unit-файлы из /usr/lib/systemd. Можно, конечно, указывать в файлах конфигурации не $MOUNTD_PORT, а MOUNTD_PORT_ARG="-p 12345", но это как-то не очень красиво получается. Вообще, более правильно было бы использовать include-директивы или "drop-ins" (unit-файлы в директории /etc/systemd/system/*.d).
Neil продолжил вторую часть с обсуждения вопросы активации сервисов. Он отмечает, что в отличие от Upstart, установка unit-файла не означает его автоматическую активацию. Далее он обращает наше внимание на существенную разницу в активации legacy-сервисов из SysV, с помощью insserv, и в systemd. В SysV активация сервиса сопровождается проверкой на завивимости (директива Required-Start), и если сервис не активирован, но insserv выпадает с подробным сообщением, из которого понятно. что нужно сделать. Утилита для обработки SysV-скриптов из systemd действует по-другому - оно учитывает порядок, но не смотрит на наличие. Таким образом можно смело говорить, что работать SysV-скрипты в systemd будут лишь в простейших случаях, и потребуется полный переход на него.
Neil также отмечает, что несмотря на противопоставление event-based системе активации из Upstart и декларативному подходу в systemd, некоторые сервисы активируются таким образом, что сторонний непредвзятый наблюдатель не сможет отличить это от событийной модели активации. Например, mdadm активируется с помощью udev, при появлении дискового массива - это выглядит именно как событие.
Дальше Neil обращает внимание на недоработку - в механизме socket activation отсутствует возможность активации не с предопределенного, а с произвольного номера порта. Это нужно для rpc.statd. Что интересно, в Solaris такой механизм есть.
Возвращаясь к параллелям и отличиям с Upstart, Neil продолжает анализировать активацию сервисов и отмечает, что достижение target в systemd хотя и практически неотличимо от событий Upstart ("starting"), сервисы systemd запускаются не по событиям, а сами создают списки событий ("я запускаюсь, поэтому запусти также то-то и то-то"). Зависимость тут развернутая - сервис Upstart точно знает, что за событие его запустило, в то время, как сервис systemd знает какие "события" (сервисы) оно запускает. Здесь очень интересно появление двух директив в systemd WantedBy и RequiredBy, которые являются антиподами для Wants и Requires соответственно, но в отличие от них могут использоваться лишь в секции [Install]. Эти директивы можно считать аналогом "start on" в Upstart, но интересно, что в секции [Unit] их использовать не получится. Несмотря на то, что каждое указание Wants и Requires в секции [Unit] действительно создает внутреннее представление WantedBy и RequiredBy в зависимых сервисах, явное их использование не допускается.
Neil продолжает с интересной задачей - условный запуск сервиса (запускать лишь в каком-то случае, иначе запускать другой сервис).
Оказалось, что без вмешательства суперпользователя это в общем случае нерешимо. Однако, в ряде случаев, используя директиву Requisite=, удалось привязать сервис к доступности указанного target. Сервис не запускается, если не запущен target, и останавливается сразу при остановке target. Получив уже четыре разных target в составе пакета nfs-utils, Neil отмечает удобство пресетов (presets) для systemd, которые позволяют мэйнтейнерам дистрибутивов самостоятельно решать то, какие target и сервисы будут включены по умолчанию.
Подытоживая вопросы активации, Neil говорит, что systemd предоставляет довольно богатый набор директив для управления сервисами, которые покрывают даже очень сложные случаи. К сожалению, как отмечает Neil, включение и отключение сервисов не принимает во внимание файлы конфигураций из /etc/sysconfig или /etc/defaults. Также интересно, что поведение udev по запуску правил по умолчанию полностью отличается от systemd, хотя присутствует в том же пакете ПО.
Далее Neil, обладая некоторым опытом разработки языков программирования, переключается с практических аспектов, на теоретические. Он недоумевает - директивы systemd разрешены лишь в конкретных секциях, тогда зачем нужны все эти [Unit], [Service], [Install]? Ну, кроме того, чтоб unit-файл выглядет бы как ini-файл.
Neil продолжает с логическими директивами systemd, такими как ConditionPathExists, которые отчасти позволяют логические выражения, такие, как A and B and (C or D or E), но не такие, как (A or B) and (C or D). Он интересуется, почему было бы не использовать традиционные правила, вместо частичного их подмножества. Любое отклонение от общепринятого стандарта лишь усложняет изучение, хотя и понятно, что сложные логические выражения в unit-файлах не будут часто встречаться.
Однако, собственная алгебра логики, это не единственное проблематичное место. Neil отмечает огромное количество директив - Requires, RequiresOverridable, Requisite, RequisiteOverridable, Wants, BindsTo, PartOf, Conflicts, Before, After, OnFailure, PropagateReloadsTo, ReloadPropagateFrom и т.п. Он чувствует, что такое их количество, это явный признак некоей модели, скрытой от пользователя, и которую можно было бы более эффективно представлять с помощью DSL.
На этом Neil останавливается, и подводит итог. Он отмечает. что указанные менее 200 строк он написал с первой попытки, и он впервые чувствует, что его описание nfs-utils в systemd делает именно то, что нужно. Как разработчик, он отмечает, что наконец-то он обладает инструментарием и языков описания, которое позволяет ему выражать именно то, что он хочет, и сравнивая с тем, что дает разработчикам systemd, можно не обращать внимание на в основном косметические минусы.

Комментарии