Знаете, чем я сейчас занимаюсь? Пишу стартовые скрипты для systemd, и это меня бесит.
Вроде бы как мы берем операционную систему для того, чтобы экономить время на таких вещах. Вроде как пакеты должны были облегчить нам жизнь. Весьма возможно, что мой выбор операционной системы был плох, но до сегодняшнего дня жить в области Debian/Ubuntu мне было вполне комфортно.
С другой стороны, «было» — это условность. Все мы часто находимся в относительном неведении относительно того, как устроена наша операционная система. А однажды увидев код /usr/sbin/service ты уже не можешь развидеть его. Так же как и пользоваться этим инструментом.
Наверное, нужно вернуться обратно. Чтобы понять, как мы оказались в такой заднице со смесью SysV и systemd, приправленной Upstart.
TL; DR: автор ноет по поводу зоопарка из SysV, Upstart и systemd в современных дистрибутивах Debian/Ubuntu.
SysV
Казалось бы, что может быть проще? В директории /etc/init.d/ находится файл с именем службы, он отвечает за запуск и остановку. Мы делаем /etc/init.d/service stop или /etc/init.d/service start и все работает отлично.
Операционная система делает то же самое, только в зависимости от runlevel, два — так два, буду последовательно выполнять симлинки из /etc/rc2.d, которые по сути своей ведут к /etc/init.d, жизнь проста и прекрасна. Чтобы управлять последовательностью достаточно изменить сортировку файлов при помощи числа. Есть утилиты, чтобы автоматизировать создание этих симлинков.
Почему мы не могли остаться в том месте? Потому что системы изменились. Они стали, гм, сложными.
Во-первых, состояние системы ранее было практически монолитным, а сегодня может быть изменчивым. Бах — и по USB подключили сетевой адаптер. При Томпсоне такого не было! Надо реагировать, т.е. уведомить службы об этом, кого-то перезапустить, кого-то запустить, кого-то погасить.
Во-вторых, SysV было глубоко плевать на интимную жизнь программ. Он их запускал на старте, но если у тебя что-то не получалось, то это был их личные проблемы. Отлаживать такие вещи, кстати, практически невозможно. Segmentation fault? Настоящие мужчины пишут программы, которые запускаются с первого раза и не сегфолтят, слабак.
В-третьих, структура зависимостей в SysV была достаточно простая, чего не всегда хватало.
В-четвертых, старт системы не мог быть параллельным. Запуск скриптов был строго последовательный. Это легко увидеть, если посмотреть на время старта OpenSUSE, например, лохматой 12 версии.
Правда, основная особенность SysV была не только в простоте. С простотой приходили проблемы. Например, если у меня каждый запуск скрипта start или stop отдельный, то как узнать, запущена программа или нет? Ведь ей нужно послать сигнал kill, а без PID его посылать некуда.
Свежей идеей было хранить эту цифру в файле .pid, прямо ну серьезно, свежей для своих далеких лет. Однако что делать, если программа вылетела с segmentation fault? Кратко: ничего, PID надо проверить, перед тем, как использовать.
Upstart
Мне кажется, что проблемы начались как раз тут. То есть, с того, как сообщество приняло Upstart. Это и задало дальнейший тон. Но по порядку.
Upstart поддерживал события. Он мог следить и перезапускать программы. Он умел выстраивать зависимости. Ну и с параллельностью у него тоже было все в порядке.
Кроме одной, огромной бочки дегтя, о которой я скажу дальше, я не помню никаких толком претензий к Upstart. А вот бочкой было то, что разработчики софта его в целом проигнорировали.
Почему? Я не знаю. Скорее всего потому, что совместимость с SysV была приоритетом для Upstart. Поэтому разработчикам ничего не нужно было менять.
В итоге, несмотря на то, что Upstart царствовал в Ubuntu 5 лет на протяжении с 2009 до 2014 года, огромное количество софта так и не перешло на него!
С одной стороны, я не могу винить в этом только разработчиков. Они, в конце концов, пишут программы. Как лучше запускать эти программы в системе — не их дело. Однако скрипты для SysV они пишут. Хотите примеров? Посмотрите, на что похож скрипт запуска postfix в Debian. Этот код монструозен, он ужасен, это же просто страшно.
Однако еще страшнее то, что многие администраторы вообще не видят и не понимают разницы. Они пишут:
sudo service apache2 start
И свято верят, что apache2 должен стартовать. Аргх, он не должен. Понимаете? Не должен. Запустится утилита /usr/bin/service, которая примется со страшной силой угадывать, как же нужно стартовать эту службу, а потом передаст вашу просьбу SysV или Upstart. Если сможет правильно угадать, ага.
service вообще не часть пакета Upstart. Оно вообще не оттуда, но как-то уживается в этом веселом кругу. Чтобы увеличить количество ада, некоторые разработчики делают скрипты /etc/init.d ссылающимися на Upstart. Эдакий уроборос, чтобы если вдруг администратор из лесу вышел и в Ubuntu 16.04 LTS напишет
/etc/init.d/service restart
Чтобы все работало.
Отдельно следует сказать про PID. Upstart не нужен PID в файле. Почему? Потому что любой запущенный им процесс остается его дочерним. Если вдруг он вылетит, то Upstart об этом узнает. И поскольку команды запуска и остановки тоже проходят через него, то тут нет никакой проблемы.
Однако как быть с сервисами, которым нужен fork? Ну для начала их надо спросить, зачем им это? Ведь в целом, fork применялся в основном для того, чтобы детачнуться от стартовавшего их процесса, но в случае с Upstart это делать незачем. Если у нас умер init, то у нас есть чуть больше проблем, чем неработающий postfix.
Да что уж там, сейчас, когда 16.04 LTS уже здесь, как думаете, при помощи чего стартует Apache2? postfix? Еще куча всякого? SysV.
Правда, в 16.04 им помогает systemd.
systemd
В целом, мне нравится systemd, честно. Его логика мне гораздо приятнее той, что была у Upstart. Правда, если бы еще Debian взяла бы не 215 релиз, а 218, то жить было бы еще лучше, но черт с ним, мы переживем и без команды edit, если надо.
И systemd можно долго ругать, но это уже стандарт. Однако как вы думаете, что делают разработчики с systemd? В основном игнорируют.
Итак, что привнес systemd? Генераторы! Тысячи их!
Кратко, если Upstart не выпендривался, а просто повторял поведение SysV, то systemd до такого не опускается. Он берет существующий /etc/init.d/service и на основе него генерирует скрипт для systemd. Его потом и запускает.
ExecStart=/etc/init.d/service start
ExecStop=/etc/init.d/service stop
Ну вот как бы да, вот примерно вот так оно и получается. Я не буду рассказывать о том, что это далеко не всегда работает так, как надо. Вернее, стартовать оно стартует. Не вздумайте в каком-нибудь продакшене положиться на рестарт такого сервиса, мониторинг станет вашим лучшим будильником.
И да, вы же понимаете, что systemd тем более не нужен PID, но увы. В сообществе это до сих пор остается толком не понятым.
К разработчикам
Да, ребята, я согласен, еще раз, запуск программы не есть ваша забота. Однако кто, как не вы, лучше знает, как спроектировать беспроблемный старт? Ведь одно дело, если команда старта выглядит так:
ExecStart=/usr/bin/control-bin start
А совсем другое, если так:
ExecStart=/usr/sbin/postfwd2 --file=/etc/postfwd/postfwd.cf --interface=127.0.0.1 --port=10040 --shortlog --summary=600 --cache=600 --cache-rbl-timeout=3600 --cleanup-requests=1200 --cleanup-rbls=1800 --cleanup-rates=1200 --user=postfwd --group=postfwd
Давайте перестанем уже размазывать настройки между /etc/config.conf и /etc/default/service?
Давайте перестанем пытаться управлять стартом службы при помощи параметра START=yes в /etc/default/service? Нет, я понимаю, что «xyes» смотрится отличной шуткой, но надоело уже!
Давайте уже решим, что systemd — он везде. И что под него можно смело адаптироваться.
К самому себе
Смирись, тряпка, и не ной. Keep calm and systemd.
Автор: prometheus_ru