В статье "i3wm с костылями - рабочее окружение." я уже упоминал про такой супервизор сервисов как runit.

Gerrit Pape эту штуку позиционирует ещё и как замену init-у. Эту идею поддерживает и Void Linux. Однако, у меня на руках другой дистрибутив - Slackaware linux. Там естественным образом живёт и работает более классическая система инициализации - system V init. В принципе она тоже умеет в подпирание сервисов, но эта тема там не является основной фичей. Технически можно реализовать и параллельный запуск сервисов, как это сделано в сервис-менеджере ssm (бывший watchman), https://git.fleshless.org/u/spark/ssm/ или в openrc. Тем не менее, сильно заморачиваться мне вобщем-то было неохота. Собственно, один коллега по мастерхосту обращал моё вниание на runit и daemon tools (которыми были подпёрты остатки сервисов на дремучей freebsd в .m).

Тогда меня не особо впечатлял такой подход. Ну работает и работает, зачем что-то менять? Однако, в то время коллеги подсадили меня на dwm. Потом я благополучно переместился на более приятный i3wm, с которым уже живу больше 4-х лет. В какой-то момент времени мне понадобилось что-то от dbus, уже не вспомню что, но я заметил, что сессия dbus не пробрасывается в моё окружение, а если стартовать процессы через dbus-launch, то плодится много экземпляров этого самого dbus-а. Исследовав причину, я понял, что надо всё и вся запускать при логине юзера из одного скрипта. Так оно, собственно, и происходит: login manager запускает .dmrc или .xinitrc из каталога пользователя и уже оттуда вызывается de или wm.

Изначально у меня всё было настроено на выковыривание из dbus-а сессии, выставление переменных окружения, запуск i3, из которого уже стартуют все остальные сервисы, из автозагрузки. Идея классная, но получается, что при перезапуске i3 запускается ещё один набор сервисов. Не то чтобы я часто перезапускал i3, но как-то не оч. Да и есть некоторые нюансы, например, нельзя "подпереть" сервис, если он упал, то упал. (Нет, его конечно можно обернуть в "while [ 1 ]; do сервис; done", но это отдельный экземпляр баша в процессах).

Я немного призадумался и тут мне пришло в голову, что можно использовать какой-нибудь супервизор, который будет запущен от пользователя и будет порождать приложения как сервисы. Watchman, коллега настаивал на своём детище. Хоть оно и простое, но в то же время какое-то по мне несколько "странное" в конфигурировании. Openrc - сложновато. Зачем мне полноценные сервисы? Upstart - совсем не то, хоть он мне и нравится как init, но супервайзить сервисы он сам по себе вроде не умеет. Daemon tools, уже ближе, если бы я не знал, что есть runit, то взял бы поделие Бернштейна. Runit оказался идеален. Одним супервайзером можно параллельно запустить кучку сервисов и отслеживать, что они работают. Отстрелил сервис, а он его оживляет. Сам. С точки зрения конфига - всё просто, ман написан доступно. Натравил runsvdir на каталог с подкаталогами, в которых расположены стартовые скрипты и всё тип-топ. Одно требование - сервисы должны работать в форграунде, то есть не демонизироваться. И один момент- как и в случае с оборачиванием в bash, здесь тоже имеет место дополнительный процесс на каждый отслеживаемый сервис, однако runit работает асинхронно, а значит быстрее и с меньшими накладными расходами, чем баш.

Поскольку я не использую мультилогин на системе, меня вполне устраивает получившийся "менеджер" сессии. Разлогиниваешься и все приложения, запущенные от сервис-менеджера им же и прибиваются.

Тем не менее и тут есть несколько нюансов. Например, не все приложения корректно работают, когда трей пропадает, а потом возвращается. Индикатор раскладки xxkb как раз так себя и ведёт. Какое решение в данном случае? Зависимости. То есть xxkb зависит от fbpanel. В текущей версии runit - 2.1.2 - не собираются 2 утилиты svwaitup и svwaitdown, с помощью которых и можно реализовать эти самые зависимости. Они тупо ждут (с таймаутом) пока такой-то сервис не подымется или пока такой-то сервис не перестанет работать с т.зр. runit. Тем не менее в дереве сорцов эти утилиты есть.

Оказалось, чтобы их собрать надо было внести тривиальные правки в пару мест и вуаля. Мне было лениво разбираться, почему Gerrit отключил возможность сборки этих двух утилит, тем более, что на первый взгляд они работают.

Собственно, как раз когда я обнаружил, что в природе есть эти 2 утилиты, я обнаружил, что уже есть более свежая версия runit, есть патчи от debian и void linux, которые правят некоторые шероховатости в работе runit. Пока что я собрался с новым runit-ом и вроде бы оно работает в том числе с зависимостями, то есть при ронянии fbpanel завершаются всякие nm-applet, xxkb, pasystray, parcellite, а при последующем запуске они взлетают - это как раз то, что мне надо.

Естественно, я пользую возможности runit и для системных сервисов. Для тех, что не шататные, например bird или chrony. Но пока что возможность создавать зависимости для системных сервисов мне не пригодилась.

В завершение этой заметки хочется сказать, что на самом деле для цели создания пользовательской сессии используется logind, но есть один нюанс, по-классике его используют в связке с systemd и pam, а в текущей стабильной версии slackware нету ни того, ни другого. И если от systemd logind отвязать можно, то вот отвязать от pam вряд ли получится. А тащить pam в работающую систему что-то не очень охота, есть некоторый шанец что-то сломать, хотя в slackware можно завезти pam начиная чуть ли не с 13-й версии, а то и раньше (процесс хоть ине штатный, но отлаженный неплохо). Но конкретно в данном случае, следуя принципам slackware, проще притащить runit и завернуть нужные вещи через него, точечно, чем тащить кучу разных компонентов и перепахивать систему.

Next Post