Supervisord и forever больше не нужны. Systemd

    В статье речь будет идти о systemd, который вошел в Debian 8 jessie. Я пишу о Debian, потому что пользуюсь именно им. Пишу о systemd не потому что его фанат, но некоторые вещи меня действительно радуют.

    Так почему же больше не нужны 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
               └─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
               └─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
               └─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.
    Поделиться публикацией
    Похожие публикации
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 66
    • +6
      Хабротвит?
      • +26
        Править сервис-файлы в [/usr]/lib/systemd/system — очень плохая идея, т.к. это vendor-файл, который перезапишется при обновлении.

        Для оверрайда используется /etc/systemd/system, куда можно поместить свой вариант сервис-файла. Но и это не совсем правильно, т.к. требует дублирования всего файла (можно решить инклюдом, но это костыльно).

        Самый правильный подход для указанной в статье задачи — использовать drop-in'ы:

        coreos.com/os/docs/latest/using-systemd-drop-in-units.html

        Ну и, конечно, читать документацию. В systemd есть много чего интересного и полезного, благодаря чему не нужно танцевать с бубном, как это делалось раньше.
        • 0
          Я ничего не имею против systemd, но, чтобы заменить supervisor, он должен обслуживать таски простых пользователей от их имени, не от root и без помощи sudo. Возможно ли такое?
          • +6
            Да, вот ман например: wiki.archlinux.org/index.php/Systemd/User
            • 0
              Спасибо. Это действительно то, что нужно. systemd развивается так быстро, что за всеми фичами не уследишь. :) Я сейчас запускаю uwsgi, paster, celeryd, haystack на своём хостинге (Debian 8) при помощи supervisord. Пожалуй, стоит перенастроить это всё на systemd и сэкономить немного памяти.

              Теперь попросим piromanlynx обновить соответствующим образом примеры в этой статье. Иначе заявленная тема не будет раскрыта. :)
              • –1
                Ну в случае как раз Ваших сервисов, которых еще нет в systemd (в отличне от ssh), Вы должны как раз класть конфиги в /lib/systemd/system/*.service

                Так что, для Вас тема раскрыта ;-)
                • 0
                  Как я понимаю, мне нужен не /lib/systemd/system/, а ~/.config/systemd/user/, и ещё “systemd --user” плюс нечто, называемое lingering. Именно это заменяет supervisord в его главном назначении: демонизировать пользовательские скрипты, отделяя их от пользовательской сессии.
                  • 0
                    демонизировать пользовательские скрипты, отделяя их от пользовательской сессии

                    т.е. Вам интересно запускать демон от имени пользователя или заменить nohup… &?
                  • 0
                    Я имею в виду, что ещё не разобрался до конца, как это сделать, но зато хорошо знаю, что я хочу. Смысл всей этой возни − запускать и перезапускать бэкенд-вебсервер и периодические задачи, обслуживающие сайт, от лица того же пользователя, который осуществляет деплоймент и тестирование. Это должен быть пользователь с минимальными привилегиями. Это ниша supervisor.
                    • 0
                      Есть еще вариант в секции [Service] добавить

                      User=<username to run as>
                      • 0
                        т.е. если Ваша задача просто запускать демон от юзера — то все что написано выше в /lib/systemd/system/ только добавить опцию User= в секцию Service. Или я Вас не понял
                        • 0
                          Да, технически этого достаточно.

                          Административно − если на одном сервере несколько пользователей (команд) осуществляют развёртывание, то логичнее будет использовать для них отдельные места для хранения юнитов. Наверное.

                          В любом случае спасибо за статью, она заставила меня заинтересоваться systemd с немного неожиданной для меня точки зрения.
                          • 0
                            Пожалуйтса!

                            Административно, мне кажется, что включать/выключать сервисы все же лучше силами сисадмина с рутом, который знает что делает, чем силами команд разработки. Они же все равно потом побегут к админу, но только что бы чинить.
                            • 0
                              На самом деле нужно и то и другое. Во время разработки и тестов должен всё настраивать тот, кто всё это разрабатывает. Когда оно уже пошло под нагрузку и слежение за тем, чтобы оно не падало стало обязанностью админа — всё делает админ.
                          • +1
                            У меня аналогичная задача. Постараюсь описать её понятнее.
                            Имеется некая система состоящая из нескольких приложений (веб-приложение, менеджер фоновых задач, какой нибудь асинхронный нотификатор на веб-сокетах и т.д.). Требуется работать с этой системой имея только права обычного пользователя. Для этого нужно, что бы пользователь мог запускать/останавливать любые процессы, добавлять/редактировать/удалять список запускаемых процессов.
                            Именно эти хотелки хорошо решал supervisor. Достаточно было один раз настроить из под root-а авто-запуск под указанным пользователем отдельного процесса supervisord, конфигурация которого доступна для редактирования пользователю.
                            Если в systemd есть аналогичные возможности, тогда действительно — supervisor «больше не нужен».
                            • 0
                              Да, как раз для Вашей задачи привели выше ссылочку на wiki.archlinux.org
                              • 0
                                В systemd есть аналогичные возможности потому что примерно эту же задачу нужно решать для самого обычного десктопа: нужно следить, чтобы всякие процессы, которые кнопочки рисуют не дохли, но при этом если вдруг у кого две сессии они бы друг другу не мешали.
                                • +1
                                  Чтобы это мог делать обычный пользователь, сначала администратор должен разрешить автоматический старт процессов этого пользователя:
                                  loginctl enable-linger _USERNAME_
                                  


                                  А потом пользователь сам может определять правила старта процессов через юниты: ~/.config/systemd/user/

                                  wiki.archlinux.org/index.php/Systemd/User#Automatic_start-up_of_systemd_user_instances
                            • +4
                              Размещать конфиги в /lib/systemd/system/*.service, т.е. там, где их не стоит размещать — неправильно. Кастомные конфиги живут в /etc.
                              • 0
                                del
                        • +3
                          [irony] Ухты, systemd добрался до супервизоров! Поттеринг, гори в аду! [/irony]
                          • –4
                            Громкое заявление, но есть такие как я и мои коллеги, например, у нас куча серверов маков и линуксов и тупо не получиться пользоватся systemd по причине того что он не везде есть и его нельзя поставить. Мы сами пользуемся супервизором https://github.com/kostya/eye, и там есть такие замечательные вещи как задержки при запуске/останове приложений, обновление множества конфигов одним действием, цепочки сигналов (чтобы прибивать процессы которые повисли разными способами с таймаутами), опять же всё это нужно с правами обычных юзеров и много чего другого. Не знаю насколько типичны или нетипичны наши хотелки, но нам systemd в принципе не сможет подойти.
                            • +2
                              задержки при запуске/останове приложений

                              И это есть в systemd

                              обновление множества конфигов одним действием

                              Не очень понял в чем суть

                              опять же всё это нужно с правами обычных юзеров

                              И это может systemd

                              цепочки сигналов (чтобы прибивать процессы которые повисли разными способами с таймаутами)

                              А это вообще может быть очень чревато и печально, особенно если SIGKILL, особенно если на высокой нагрузке.

                              серверов маков и линуксов и тупо не получиться пользоватся systemd по причине того что он не везде есть и его нельзя поставить

                              Ну проблема разрозненной инфрастуктуры… В ней обычно не systemd и не какое то другое решение виноваты. Это обычная ситуация в российском IT, ну как проблема с дорогами в РФ.
                              • 0
                                «задержки при запуске/останове приложений»
                                То есть мне нужно запустить 20 экземпляров какого-то скрипта и чтобы он не сразу их все стартовал/останавливал, а по очереди? Есть такое?

                                «обновление множества конфигов одним действием»
                                Я имел в виду что есть несколько взаимосвязанных микросервисов, я изменил количество процессов разных типов которые нужно стартовать, выполнил какую-то команду для загрузки этих конфигов и сразу же лишние процессы прибьются, а недостающие запустятся.

                                «опять же всё это нужно с правами обычных юзеров

                                И это может systemd»
                                я был бы благодарен за ссылку как это сделать

                                «А это вообще может быть очень чревато и печально, особенно если SIGKILL, особенно если на высокой нагрузке.»
                                В принципе согласен, но есть, например, скрипт (или группа скриптов), который ненадёжен, может повиснуть или течёт по памяти, на правку времени ни у кого нет, а работать должен прямо сейчас.

                                «Ну проблема разрозненной инфрастуктуры… В ней обычно не systemd и не какое то другое решение виноваты. Это обычная ситуация в российском IT, ну как проблема с дорогами в РФ.»
                                Это проблема в любом более менее долгоживущем IT в компаниях где меняются люди отвечающие за закупку железа и/или софта.
                                • 0
                                  1) есть. пишешь несколько сервисов, описываешь 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.
                                  • 0
                                    Для youlose нужен, все-таки, самописный скрипт, который конкретно его задачи будет решать. Слишком специфичные вещи не стоит костылить. Частично systemd, но над ним можно еще что-то.

                                    Но хотелось бы задать автору вопрос именно по (1). Есть задача — запустить 20 копий скрипта myscript.py. И контролировать что они не упали — перезапускать. Как может systemd это сделать? Писать 20 одинаковых сервисов? Но это, извините, как раз и костыль. Негибко совсем.
                                    • +1
                                      Для этого есть шаблоны. systemd.unit(5), смотреть на тему template.
                            • +3
                              Слушайте, а я чего-то не понимаю, или это было уже в старом добром init? Ну, типа, вписать нужную строчку в inittab и init сам что надо поперезапускает?
                              • +5
                                Именно так. Изначально SysV init начался ровно с этой идеи. Но там не было обработки зависимостей. И вместо того, чтобы придумать как добавить в SysV init обработку зависимостей большинство демонов начало запускаться одним развесистым скриптом с кучей костылей занимающим одну строчку в inittab. А потом туда добавили ещё костылей. И ещё. Через многие годы люди уже и забыли о том, какая изначально под всем эти лежала идея и что «костыли сбоку» — это всего лишь костыли.

                                А systemd — это, в приципе, «возвращение к истокам».
                                • +1
                                  При этом никто не пошёл в список рассылки/багзиллу sysvinit и не попытался его проапгрейдить. Not invented here, чо… Грустно это всё как-то…
                                  • 0
                                    Я редко видел, чтобы проекты «ушедшие не туда» кто-то поднимал бы «под старым знаменем». Лучший вариант — это когда новому проекту в какой-то момент дают имя старого (gcc 2.95, да), но чаще — просто создаётся новый проект. Всё просто: если вы планируете радикальную переделку, то в старом проекте вам, скорее всего, никто это делать не даст (в лучшем случае в какой-нибудь экспериментальной ветке попробовать разрешат), а когда оно уже «взлетело»… зачем вам старый проект-то?
                              • +1
                                «Неубиваемые» сервисы без постоянного мониторинга — это палка о двух концах. Достаточно кому-то накосячить (например, в конфигах), чтобы сервис не мог запуститься — и его всё время будут перезапускать, забивая дисковое пространство под логи ошибками. Если этого вовремя не заметить, могут быть уже проблемы нехватки этого пространства. Полагаю, на продакшнах правильнее уведомлять админа об остановке сервиса, чтобы тот посмотрел на причины и принял соответствующее решение.
                                • +1
                                  Ну наверное попытася взлететь назад — это первое что должно случится с сервисом. А мониторинг никто и не отменял. Ну придет админ через полчаса, увидит, что сервис работает — пойдет курить дальше. Или увидит что не работает, но полчаса ничего не испортят. А пытатся взлететь надо.
                                  А мониторить это совсем легко и просто. Есть отличная метрика — сколько новых pid появилось по сравнению с предыдушим состоянием и сколько пропало. Я эту метрику собираю со всех машин — для разных ролей машин конечно движуха разная, например на машинах с nginx пиды почти не меняются, а вот с php-fpm или postfix есть регулярная ротация. Главное корректно настроить Alert в мониторинге.
                                  • 0
                                    А каким образом собираете, если не секрет?
                                    • +1
                                      zabbix + просто скрипт на bash, который использует ps aux, grep и временный файлик. Скрипт отдает 2 числа — сколько прибавилось, сколько убавилось.
                                    • –4
                                      А потом при расследовании очередного инцидента выяснится, что за те полчаса, пока админ курил, сервис сообщениями об ошибках при постоянном перезапуске забил всё дисковое пространство в разделе для логов, другим работающим сервисам ничего не осталось, и они тоже начали вылетать. У нас было нечто похожее.
                                      • +1
                                        Ну так ограничивать нужно количество попыток.
                                        • 0
                                          Про что и речь. Такие возможности у того же systemd есть?
                                          • +5
                                            Конечно есть. Странно, что автор их не указал. StartLImit* в systemd.service(5). Более того, лимиты по умолчанию включены, так что если включаешь рестар, оно не будет тупо бесконечно дёргаться.

                                            Вот количество перезапусков может понадобится подстроить под сервис, это да.
                                            • 0
                                          • 0
                                            Ну странный у вас /var/log какой то, что его за полчаса забило.
                                            Да и умные люди делают по умному — один сервис — одна виртуалка. И пусть она хоть упадет.
                                            • 0
                                              journald автоматически ротейтит бинарные логи. размер высчитвывается следующим образом: www.freedesktop.org/software/systemd/man/journald.conf.html#SystemMaxUse=

                                              Но в journald есть один фатальный недостаток. Если логи сыпятся слишком быстро, то он их может пропускать и не обрабатывать. С другой стороны, может это и не недостаток, а достоинство.
                                              • 0
                                                Если посмотреть на mature syslog (rsyslog, syslog-ng), то они при burst'е (например, при когда что-то сломалось и привело к обильному срачу в логах) прекрасно теряют данные. Так что это имплицитная особенность основных систем логгирования.
                                                • +1
                                                  Даже с выключенными настройками

                                                  RateLimitInterval=30s
                                                  RateLimitBurst=1000

                                                  ?
                                                • 0
                                                  Ну не обязательно за полчаса — выходные, например, длятся несколько дольше. А архитектура сервисов бывает всякая — кто во что горазд.
                                          • 0
                                            ок, пробую 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
                                            


                                            Что-то недопонял я?
                                            • 0
                                              У тебя лог не полный.
                                              • 0
                                                А как полный получить?
                                                • 0
                                                  Ну посмотри, у тебя он на Connection обрывается. Дальше то что?
                                                  • 0
                                                    Так дальше-то только alex@playground $ | — prompt и курсор.
                                                    • 0
                                                      «Failed to get D-Bus connection: Connection». А дальше что? Только слово Connection? Больше никакой информации не было?
                                            • +1
                                              Это всё конечно замечательно, пока не выходит на сцену какой-нибудь этак docker…
                                              • +2
                                                А что с ним не так? У меня прекрасно контейнеры докера из-под сабжа запускаются.
                                                • –5
                                                  Не говорите слово docker. Он настолько адски сырой, что его и трогать пока страшно.
                                                  P.S. потрогал, посмотрел, попользовал — отложил в ящик, через 1-2 года достану.
                                                  • +2
                                                    У меня на паре некритичных вещей работает — вроде нормально пока. Более серьезные товарищи его и в продакшн используют по слухам.
                                                    • 0
                                                      Слухи подтверждаю.
                                                      • 0
                                                        У нас небольшая часть продакшна в докере, но не всё гладко.
                                                        При большой cpu-активности была неприятная бага в cpuacct cgroups, приводившая к панике. Словить её можно и просто используя cgroups.
                                                        Также нарывались на панику при использовании короткоживущих контейнеров (бага с удалением netns при использовании conntrack+nat).
                                                      • +1
                                                        А что именно с ним не так?
                                                        • 0
                                                          Давсе так… Уже год в продакшене у меня… Кака часы…
                                                      • 0
                                                        У меня были проблемы с запуском (systemd не запущен, а как его там запустить — не понятно) + как вы решили проблему с уничтожением контейнера? «while true»?

                                                        Или вы про запуск контейнеров через systemd? Я вот пишу про запуск юнитов изнутри контейнера…
                                                        • 0
                                                          > Или вы про запуск контейнеров через systemd?

                                                          Да, именно так.
                                                          Внутри контейнеров пока supervisor, руки все никак не дойдут там поковырять.
                                                          • 0
                                                            Что ж тогда понятно.

                                                            Удачи вам, от всей души, это, как оказалось, не самое простое занятие :(
                                                            • 0
                                                              Меня вот терзает мысль, а может быть внутри контейнеров вообще убрать его нафиг и ничем не заменять?
                                                              Наличие процесса внутри можно проверять, например, через /proc/1/cgroup. Тут нужно покопаться еще.
                                                              • 0
                                                                Так контейнер сразу же останавливается, вроде бы, если процесс с pid 1 завершается?
                                                    • 0
                                                      Для этих целей, есть ssh.socket
                                                      А авторестарт такого сервиса — избыточно

                                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.