Что: 6d663c82fdf9b0534da062f02f639730dcc235f1
Когда: 2020-08-21 13:50:00+03:00
Темы: systemd
Давно не писал про systemd... ибо он просто не работает Вчера с коллегами поднимали NSD сервер на современном CentOS. systemctl start nsd отрабатывает, успешный код возрата, ничего не говорит. А демона нет. В логах, выясняется, что nsd то в принципе не запускался потому что :53 порт занят. Если запустить nsd руками, то он честно возвращает плохой код. Что это значит? Значит что systemd даже с своей первоочередной задачей не справился, не работает -- отвечает что всё хорошо, хотя демон честно вышел с ошибкой. Ну и как с этим дерьмом работать? Вопрос риторический конечно же и для меня это как Windows -- с этим я просто не связываюсь.
From: kmeaw Date: 2020-09-11 21:13:28Z Сталкивался с той же проблемой несколько лет назад, когда писал cgroup manager, и хотел уметь запускать его из sysvinit, runit и upstart. Концептуально проблема с том, что сервис может или сам заниматься демонизацией, или отдать эту задачу супервизору. В первом случае это усложняет работу супервизора: У Upstart есть хак, который подключается через ptrace к процессу и ждёт, пока он сделает fork или double fork. В systemd есть Type=forking, но деталей реализации я не знаю. У runit вообще нет никакого адекватного способа супервайзить такие процессы. Приходится писать бесконечный цикл, который раз в секунду проверяет, запущен ли процесс, и при этом не забывать о возможных гонках за pid. Также программа самостоятельно решает, куда она запишет pid-файл. Первый случай хорош только для init-скриптов. В этом случае не надо использовать start-stop-daemon --background --make-pidfile, а достаточно просто запустить программу, а дальше она всё сделает сама. Ещё далеко не все разработчики умеют правильно демонизировать процессы. Кто-то забудет файловые дескрипторы позакрывать или ещё что-нибудь. Кажется в nginx была проблема, которая проявлялась, если после демонизации поменять размер окна эмулятора терминала - рабочему процессу nginx прилетал SIGWINCH, и он завершался. Во втором случае это усложняет процедуру оповещения пользователя об успешном старте: Пользователь ожидает, что запуск service XXX start выдаст ошибку, если что-то где-то неправильно сконфигурировано, и нормальная работа сервиса невозможна. Для этого процесс сначала готовит себе окружение (читает/парсит конфиг, загружает секреты и биндит сокеты, требующие root/capabilities, готовит сетевые интерфейсы и так далее). В тот момент, когда сервис (почти) готов работать, он сообщает супервизору о готовности и переходит в рабочий режим. Upstart предполагает, что процесс пошлёт себе SIGSTOP. Мне это решение очень нравится — его легко использовать даже в ограниченных окружениях (chroot, namespaces), и процессы обычно так не делают в любых других ситуациях. В systemd есть шина, на которую сервис должен послать сообщение о своей готовности. Для этого нужна библиотека, которая умеет к ней подключаться и доступ к сокету шины. Я хотел затащить вариант Upstart в systemd, но нашёл тикет, в котором кто-то уже предлагал такую возможность, и Леннарт Поттеринг закрыл его с WONTFIX с мотивировкой "не вижу, чем вариант с raise(SIGSTOP); проще варианта с sd_notify("READY=1");". Кажется ещё в systemd и upstart есть возможность подождать указанное в конфиге время. Если сервис упадёт раньше, чем это время пройдёт, значит он сломался. В случае с init-скриптами обычно вставляют цикл, который проверяет живость процесса и готовность сервиса работать — либо по маркерному файлу, либо попыткой послать в него ping-запрос. С runit я нормального решения не придумал. В итоге пошёл на TOCTOU-компромисс, и просто вставил вызов configtest перед запуском. Правда это никак не решает проблему с тем, что пользователь делает up на сервис. Приходится делать обёртку, которая позволяет донести до пользователя ошибку. Наконец, есть альтернативный подход - переложить всю подготовительную работу на супервизор. Пусть он кладёт секреты в environment, открывает сокеты и запускает configtest. Увы, он не обладает должной универсальностью — нельзя предсказать все хотелки сервиса при разработке супервизора. Хотя runit/daemontools и systemd пытаются, предоставляя tcpsvd (socket activation), envdir (EnvironmentFile=), chpst (куча всего в sytsemd.exec) и прочее. Из всего этого можно сделать вывод, что проблема вполне реальна. И приходится либо решать её каждый раз (или в коде демонизации сервиса, или в init-скрипте, проверяющим успешность старта), что часто приводит к ошибкам, либо положиться на умный супервизор. Ни sysvinit, ни runit не предоставляют удобных механизмов для уведомления пользователя. А Upstart и systemd требуют кооперации со стороны сервиса, что не всегда приемлимо для разработчика, особенно в случае необходимости работать на широком спектре систем.
From: Sergey Matveev Date: 2020-09-13 13:13:26Z
Сгенерирован: SGBlog 0.34.0