Так почему же больше не нужны supervisord и forever?
Задача supervisord и его аналога написанного на nodejs — forever: демонизировать недемонизируемое и поднимать, когда оно падает. Эти задачи сейчас выполняет штатный systemd. Что в этом хорошего? Ну как минимум не нужны дополнительные инструменты (которых кстати не только два упомянутых) и есть штатное системное средство для решения таких задач.
Например очень легко настроить таким образом sshd, чтобы он поднимался в случае падения или kill. Нам нужно найти .service файл нашего sshd. Для этого выполним:
root@lynx:~# systemctl status ssh
? ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since Fri 2015-10-09 20:09:29 UTC; 55s ago
Main PID: 26884 (sshd)
CGroup: /system.slice/ssh.service
L-26884 /usr/sbin/sshd -D
Oct 09 20:09:29 lynx sshd[26884]: Server listening on 0.0.0.0 port 22.
Oct 09 20:09:29 lynx sshd[26884]: Server listening on :: port 22.
Собственно /lib/systemd/system/ssh.service и есть нужный нам файл. Вот такое его содержимое по умолчанию:
[Unit]
Description=OpenBSD Secure Shell server
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
[Install]
WantedBy=multi-user.target
Alias=sshd.service
В секции Service есть специальная опция “Restart” она как раз указывает, в каких случаях перезапускать сервис автоматически. Мы можем написать туда:
Restart=always
И при любом падении или попытке не взлететь sshd будет перезапущен. Чтобы изменения в файле вступили в силу, нужно выполнить:
root@lynx:~# systemctl daemon-reload
root@lynx:~# systemctl restart ssh
Теперь проверим, что сервис работает:
root@lynx:~# systemctl status ssh
? ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since Fri 2015-10-09 20:09:29 UTC; 3min 58s ago
Main PID: 26884 (sshd)
CGroup: /system.slice/ssh.service
L-26884 /usr/sbin/sshd -D
Oct 09 20:09:29 lynx sshd[26884]: Server listening on 0.0.0.0 port 22.
Oct 09 20:09:29 lynx sshd[26884]: Server listening on :: port 22.
Давайте убьем sshd и посмотрим как он запустился снова:
root@lynx:~# killall sshd
root@lynx:~# systemctl status ssh
? ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled)
Active: active (running) since Fri 2015-10-09 20:13:47 UTC; 1s ago
Main PID: 14123 (sshd)
CGroup: /system.slice/ssh.service
L-14123 /usr/sbin/sshd -D
Oct 09 20:13:47 lynx sshd[14123]: Server listening on 0.0.0.0 port 22.
Oct 09 20:13:47 lynx sshd[14123]: Server listening on :: port 22.
Видите, PID отличается — это говорит о том, что sshd действительно сдох, а systemd запустил его заново.
Поздравляю! Теперь Ваш sshd будет невозможно убить kill-ом и Ваш сервер будет доступен по ssh даже в случае убийства sshd.
Комментарии (65)
pfactum
10.10.2015 16:42+26Править сервис-файлы в [/usr]/lib/systemd/system — очень плохая идея, т.к. это vendor-файл, который перезапишется при обновлении.
Для оверрайда используется /etc/systemd/system, куда можно поместить свой вариант сервис-файла. Но и это не совсем правильно, т.к. требует дублирования всего файла (можно решить инклюдом, но это костыльно).
Самый правильный подход для указанной в статье задачи — использовать drop-in'ы:
coreos.com/os/docs/latest/using-systemd-drop-in-units.html
Ну и, конечно, читать документацию. В systemd есть много чего интересного и полезного, благодаря чему не нужно танцевать с бубном, как это делалось раньше.
Tanner
10.10.2015 16:46Я ничего не имею против systemd, но, чтобы заменить supervisor, он должен обслуживать таски простых пользователей от их имени, не от root и без помощи sudo. Возможно ли такое?
farcaller
10.10.2015 16:48+6Да, вот ман например: wiki.archlinux.org/index.php/Systemd/User
Tanner
10.10.2015 17:06Спасибо. Это действительно то, что нужно. systemd развивается так быстро, что за всеми фичами не уследишь. :) Я сейчас запускаю uwsgi, paster, celeryd, haystack на своём хостинге (Debian 8) при помощи supervisord. Пожалуй, стоит перенастроить это всё на systemd и сэкономить немного памяти.
Теперь попросим piromanlynx обновить соответствующим образом примеры в этой статье. Иначе заявленная тема не будет раскрыта. :)piromanlynx
10.10.2015 17:24-1Ну в случае как раз Ваших сервисов, которых еще нет в systemd (в отличне от ssh), Вы должны как раз класть конфиги в /lib/systemd/system/*.service
Так что, для Вас тема раскрыта ;-)Tanner
10.10.2015 17:37Как я понимаю, мне нужен не /lib/systemd/system/, а ~/.config/systemd/user/, и ещё “systemd --user” плюс нечто, называемое lingering. Именно это заменяет supervisord в его главном назначении: демонизировать пользовательские скрипты, отделяя их от пользовательской сессии.
piromanlynx
10.10.2015 17:44демонизировать пользовательские скрипты, отделяя их от пользовательской сессии
т.е. Вам интересно запускать демон от имени пользователя или заменить nohup… &?
Tanner
10.10.2015 17:44Я имею в виду, что ещё не разобрался до конца, как это сделать, но зато хорошо знаю, что я хочу. Смысл всей этой возни ? запускать и перезапускать бэкенд-вебсервер и периодические задачи, обслуживающие сайт, от лица того же пользователя, который осуществляет деплоймент и тестирование. Это должен быть пользователь с минимальными привилегиями. Это ниша supervisor.
piromanlynx
10.10.2015 17:46т.е. если Ваша задача просто запускать демон от юзера — то все что написано выше в /lib/systemd/system/ только добавить опцию User= в секцию Service. Или я Вас не понял
Tanner
10.10.2015 18:00Да, технически этого достаточно.
Административно ? если на одном сервере несколько пользователей (команд) осуществляют развёртывание, то логичнее будет использовать для них отдельные места для хранения юнитов. Наверное.
В любом случае спасибо за статью, она заставила меня заинтересоваться systemd с немного неожиданной для меня точки зрения.piromanlynx
10.10.2015 18:03Пожалуйтса!
Административно, мне кажется, что включать/выключать сервисы все же лучше силами сисадмина с рутом, который знает что делает, чем силами команд разработки. Они же все равно потом побегут к админу, но только что бы чинить.khim
11.10.2015 23:41На самом деле нужно и то и другое. Во время разработки и тестов должен всё настраивать тот, кто всё это разрабатывает. Когда оно уже пошло под нагрузку и слежение за тем, чтобы оно не падало стало обязанностью админа — всё делает админ.
Cykooz
10.10.2015 18:18+1У меня аналогичная задача. Постараюсь описать её понятнее.
Имеется некая система состоящая из нескольких приложений (веб-приложение, менеджер фоновых задач, какой нибудь асинхронный нотификатор на веб-сокетах и т.д.). Требуется работать с этой системой имея только права обычного пользователя. Для этого нужно, что бы пользователь мог запускать/останавливать любые процессы, добавлять/редактировать/удалять список запускаемых процессов.
Именно эти хотелки хорошо решал supervisor. Достаточно было один раз настроить из под root-а авто-запуск под указанным пользователем отдельного процесса supervisord, конфигурация которого доступна для редактирования пользователю.
Если в systemd есть аналогичные возможности, тогда действительно — supervisor «больше не нужен».khim
11.10.2015 23:43В systemd есть аналогичные возможности потому что примерно эту же задачу нужно решать для самого обычного десктопа: нужно следить, чтобы всякие процессы, которые кнопочки рисуют не дохли, но при этом если вдруг у кого две сессии они бы друг другу не мешали.
sply
12.10.2015 00:21+1Чтобы это мог делать обычный пользователь, сначала администратор должен разрешить автоматический старт процессов этого пользователя:
loginctl enable-linger _USERNAME_
А потом пользователь сам может определять правила старта процессов через юниты: ~/.config/systemd/user/
wiki.archlinux.org/index.php/Systemd/User#Automatic_start-up_of_systemd_user_instances
pfactum
10.10.2015 21:24+4Размещать конфиги в /lib/systemd/system/*.service, т.е. там, где их не стоит размещать — неправильно. Кастомные конфиги живут в /etc.
namespace
10.10.2015 19:53+3[irony] Ухты, systemd добрался до супервизоров! Поттеринг, гори в аду! [/irony]
youlose
11.10.2015 00:49-4Громкое заявление, но есть такие как я и мои коллеги, например, у нас куча серверов маков и линуксов и тупо не получиться пользоватся systemd по причине того что он не везде есть и его нельзя поставить. Мы сами пользуемся супервизором https://github.com/kostya/eye, и там есть такие замечательные вещи как задержки при запуске/останове приложений, обновление множества конфигов одним действием, цепочки сигналов (чтобы прибивать процессы которые повисли разными способами с таймаутами), опять же всё это нужно с правами обычных юзеров и много чего другого. Не знаю насколько типичны или нетипичны наши хотелки, но нам systemd в принципе не сможет подойти.
piromanlynx
11.10.2015 00:55+2задержки при запуске/останове приложений
И это есть в systemd
обновление множества конфигов одним действием
Не очень понял в чем суть
опять же всё это нужно с правами обычных юзеров
И это может systemd
цепочки сигналов (чтобы прибивать процессы которые повисли разными способами с таймаутами)
А это вообще может быть очень чревато и печально, особенно если SIGKILL, особенно если на высокой нагрузке.
серверов маков и линуксов и тупо не получиться пользоватся systemd по причине того что он не везде есть и его нельзя поставить
Ну проблема разрозненной инфрастуктуры… В ней обычно не systemd и не какое то другое решение виноваты. Это обычная ситуация в российском IT, ну как проблема с дорогами в РФ.youlose
11.10.2015 01:48«задержки при запуске/останове приложений»
То есть мне нужно запустить 20 экземпляров какого-то скрипта и чтобы он не сразу их все стартовал/останавливал, а по очереди? Есть такое?
«обновление множества конфигов одним действием»
Я имел в виду что есть несколько взаимосвязанных микросервисов, я изменил количество процессов разных типов которые нужно стартовать, выполнил какую-то команду для загрузки этих конфигов и сразу же лишние процессы прибьются, а недостающие запустятся.
«опять же всё это нужно с правами обычных юзеров
И это может systemd»
я был бы благодарен за ссылку как это сделать
«А это вообще может быть очень чревато и печально, особенно если SIGKILL, особенно если на высокой нагрузке.»
В принципе согласен, но есть, например, скрипт (или группа скриптов), который ненадёжен, может повиснуть или течёт по памяти, на правку времени ни у кого нет, а работать должен прямо сейчас.
«Ну проблема разрозненной инфрастуктуры… В ней обычно не systemd и не какое то другое решение виноваты. Это обычная ситуация в российском IT, ну как проблема с дорогами в РФ.»
Это проблема в любом более менее долгоживущем IT в компаниях где меняются люди отвечающие за закупку железа и/или софта.kay
12.10.2015 11:171) есть. пишешь несколько сервисов, описываешь Require и After для каждого и устанавливаешь TimeoutStartSec.
2) тут не совсем понял, но для этого существуют target: www.freedesktop.org/software/systemd/man/systemd.target.html
3) www.freedesktop.org/software/systemd/man/systemd.exec.html#User=
4) Пишешь задачу timers (замена cron, примеры тут coreos.com/os/docs/758.1.0/scheduling-tasks-with-systemd-timers.html) и выполняешь необходимую последовательность действий. Хоть каждую секунду, чего cron не позволял сделать.
5) В systemd еще остались косяки, но сильно жить в production они уже не мешают. И всё-таки я за то, чтобы systemd заменил всяческие питоновые supervisord или, простите, nodejs.baldr
12.10.2015 15:26Для youlose нужен, все-таки, самописный скрипт, который конкретно его задачи будет решать. Слишком специфичные вещи не стоит костылить. Частично systemd, но над ним можно еще что-то.
Но хотелось бы задать автору вопрос именно по (1). Есть задача — запустить 20 копий скрипта myscript.py. И контролировать что они не упали — перезапускать. Как может systemd это сделать? Писать 20 одинаковых сервисов? Но это, извините, как раз и костыль. Негибко совсем.
mickvav
11.10.2015 21:33+3Слушайте, а я чего-то не понимаю, или это было уже в старом добром init? Ну, типа, вписать нужную строчку в inittab и init сам что надо поперезапускает?
khim
12.10.2015 00:12+5Именно так. Изначально SysV init начался ровно с этой идеи. Но там не было обработки зависимостей. И вместо того, чтобы придумать как добавить в SysV init обработку зависимостей большинство демонов начало запускаться одним развесистым скриптом с кучей костылей занимающим одну строчку в inittab. А потом туда добавили ещё костылей. И ещё. Через многие годы люди уже и забыли о том, какая изначально под всем эти лежала идея и что «костыли сбоку» — это всего лишь костыли.
А systemd — это, в приципе, «возвращение к истокам».mickvav
12.10.2015 13:16+1При этом никто не пошёл в список рассылки/багзиллу sysvinit и не попытался его проапгрейдить. Not invented here, чо… Грустно это всё как-то…
khim
12.10.2015 16:57Я редко видел, чтобы проекты «ушедшие не туда» кто-то поднимал бы «под старым знаменем». Лучший вариант — это когда новому проекту в какой-то момент дают имя старого (gcc 2.95, да), но чаще — просто создаётся новый проект. Всё просто: если вы планируете радикальную переделку, то в старом проекте вам, скорее всего, никто это делать не даст (в лучшем случае в какой-нибудь экспериментальной ветке попробовать разрешат), а когда оно уже «взлетело»… зачем вам старый проект-то?
lubezniy
12.10.2015 00:17+1«Неубиваемые» сервисы без постоянного мониторинга — это палка о двух концах. Достаточно кому-то накосячить (например, в конфигах), чтобы сервис не мог запуститься — и его всё время будут перезапускать, забивая дисковое пространство под логи ошибками. Если этого вовремя не заметить, могут быть уже проблемы нехватки этого пространства. Полагаю, на продакшнах правильнее уведомлять админа об остановке сервиса, чтобы тот посмотрел на причины и принял соответствующее решение.
piromanlynx
12.10.2015 03:17+1Ну наверное попытася взлететь назад — это первое что должно случится с сервисом. А мониторинг никто и не отменял. Ну придет админ через полчаса, увидит, что сервис работает — пойдет курить дальше. Или увидит что не работает, но полчаса ничего не испортят. А пытатся взлететь надо.
А мониторить это совсем легко и просто. Есть отличная метрика — сколько новых pid появилось по сравнению с предыдушим состоянием и сколько пропало. Я эту метрику собираю со всех машин — для разных ролей машин конечно движуха разная, например на машинах с nginx пиды почти не меняются, а вот с php-fpm или postfix есть регулярная ротация. Главное корректно настроить Alert в мониторинге.evg_krsk
12.10.2015 05:19А каким образом собираете, если не секрет?
piromanlynx
12.10.2015 10:31+1zabbix + просто скрипт на bash, который использует ps aux, grep и временный файлик. Скрипт отдает 2 числа — сколько прибавилось, сколько убавилось.
lubezniy
12.10.2015 08:17-4А потом при расследовании очередного инцидента выяснится, что за те полчаса, пока админ курил, сервис сообщениями об ошибках при постоянном перезапуске забил всё дисковое пространство в разделе для логов, другим работающим сервисам ничего не осталось, и они тоже начали вылетать. У нас было нечто похожее.
evg_krsk
12.10.2015 08:52+1Ну так ограничивать нужно количество попыток.
lubezniy
12.10.2015 10:24Про что и речь. Такие возможности у того же systemd есть?
evg_krsk
12.10.2015 10:41+5Конечно есть. Странно, что автор их не указал. StartLImit* в systemd.service(5). Более того, лимиты по умолчанию включены, так что если включаешь рестар, оно не будет тупо бесконечно дёргаться.
Вот количество перезапусков может понадобится подстроить под сервис, это да.
kay
12.10.2015 11:23Ограничения настраиваются: www.freedesktop.org/software/systemd/man/systemd.service.html#StartLimitInterval=
piromanlynx
12.10.2015 10:27Ну странный у вас /var/log какой то, что его за полчаса забило.
Да и умные люди делают по умному — один сервис — одна виртуалка. И пусть она хоть упадет.kay
12.10.2015 11:30journald автоматически ротейтит бинарные логи. размер высчитвывается следующим образом: www.freedesktop.org/software/systemd/man/journald.conf.html#SystemMaxUse=
Но в journald есть один фатальный недостаток. Если логи сыпятся слишком быстро, то он их может пропускать и не обрабатывать. С другой стороны, может это и не недостаток, а достоинство.grossws
12.10.2015 16:27Если посмотреть на mature syslog (rsyslog, syslog-ng), то они при burst'е (например, при когда что-то сломалось и привело к обильному срачу в логах) прекрасно теряют данные. Так что это имплицитная особенность основных систем логгирования.
saamich
12.10.2015 20:59+1Даже с выключенными настройками
RateLimitInterval=30s
RateLimitBurst=1000
?
lubezniy
12.10.2015 11:43Ну не обязательно за полчаса — выходные, например, длятся несколько дольше. А архитектура сервисов бывает всякая — кто во что горазд.
Alex_At_Net
12.10.2015 05:50ок, пробую systemd. Как я понял, надо добавить пользователя в linger
sudo loginctl enable-linger alex
, что бы сессия для пользователя запускалась при загрузке системы.
Потом добавил ~/.config/systemd/user/server
$ cat .config/systemd/user/server [Unit] Description=server [Service] ExecStart=/srv/www/server/server/bin/server
Теперь надо запустить?
$ systemctl --user start server Failed to get D-Bus connection: Connection
Что-то недопонял я?kay
12.10.2015 11:32У тебя лог не полный.
Alex_At_Net
12.10.2015 12:26А как полный получить?
kay
12.10.2015 12:33Ну посмотри, у тебя он на Connection обрывается. Дальше то что?
Alex_At_Net
12.10.2015 12:51Так дальше-то только
alex@playground $ |
— prompt и курсор.kay
12.10.2015 12:57«Failed to get D-Bus connection: Connection». А дальше что? Только слово Connection? Больше никакой информации не было?
saksmt
12.10.2015 07:57+1Это всё конечно замечательно, пока не выходит на сцену какой-нибудь этак docker…
isden
12.10.2015 10:23+2А что с ним не так? У меня прекрасно контейнеры докера из-под сабжа запускаются.
piromanlynx
12.10.2015 10:29-5Не говорите слово docker. Он настолько адски сырой, что его и трогать пока страшно.
P.S. потрогал, посмотрел, попользовал — отложил в ящик, через 1-2 года достану.isden
12.10.2015 10:42+2У меня на паре некритичных вещей работает — вроде нормально пока. Более серьезные товарищи его и в продакшн используют по слухам.
grossws
13.10.2015 16:58У нас небольшая часть продакшна в докере, но не всё гладко.
При большой cpu-активности была неприятная бага в cpuacct cgroups, приводившая к панике. Словить её можно и просто используя cgroups.
Также нарывались на панику при использовании короткоживущих контейнеров (бага с удалением netns при использовании conntrack+nat).
saksmt
13.10.2015 08:46У меня были проблемы с запуском (systemd не запущен, а как его там запустить — не понятно) + как вы решили проблему с уничтожением контейнера? «while true»?
Или вы про запуск контейнеров через systemd? Я вот пишу про запуск юнитов изнутри контейнера…isden
13.10.2015 10:07> Или вы про запуск контейнеров через systemd?
Да, именно так.
Внутри контейнеров пока supervisor, руки все никак не дойдут там поковырять.saksmt
13.10.2015 22:10Что ж тогда понятно.
Удачи вам, от всей души, это, как оказалось, не самое простое занятие :(isden
13.10.2015 22:21Меня вот терзает мысль, а может быть внутри контейнеров вообще убрать его нафиг и ничем не заменять?
Наличие процесса внутри можно проверять, например, через /proc/1/cgroup. Тут нужно покопаться еще.youlose
14.10.2015 14:05Так контейнер сразу же останавливается, вроде бы, если процесс с pid 1 завершается?
tonymadbrain
Хабротвит?