Пользователь
0,0
рейтинг
10 февраля 2010 в 19:23

Администрирование → Использование runit для своих сервисов

Супервизор сервисов runit позиционируется как замена стандартным скриптам инициализации Unix.

Но на практике оказалось, что runit идеален для управления сервисами безотносительно инициализации и т.п.

Введение


Супервизор берёт на себя такой функционал, как:
  • превращение любого процесса в демон;
  • логгирование вывода процесса и ротирование логов;
  • запуск, остановка, рестарт, запрос состояния, управляющие скрипты для init.d;
  • выключение и запуск сервисов автоматически при появлении новых сервисов в списке либо удалении старых из списка;
  • возможность ведения нескольких независимых списков сервисов одновременно (например, для каждого пользователя отдельно и для системы в целом);
  • удобный API для управления сервисами.

Для большинства операционных систем runit уже входит в репозитории пакетов (apt-get install runit). Кроме того, мы имеем уже готовый набор рецептов (ссылку придётся поправить, хабр сломал её) для популярных сервисов (nginx, apache etc.).

Далее рассмотрим стандартную схему runit (которая используется по умолчанию):

Демонизация


Каждый сервис описывается отдельным каталогом /etc/sv/<название сервиса>.

обычно достаточно иметь в этом каталоге исполняемый скрипт run вида
#!/bin/bash
exec 2>&1

exec your_running_command


Важно, чтобы your_running_command не демонизировала себя (не отсоединялась от стандартных потоков stdin, stdout, stderr).

Переадресация ошибок в стандартный вывод нужна для их логгирования. Выполняется логгирование, если в каталоге /etc/sv/<название сервиса>/log/ разместить файл run вида
#!/bin/bash
LOG_FOLDER=/var/log/<название сервиса>
mkdir -p $LOG_FOLDER
exec svlogd -tt $LOG_FOLDER


Сервисы, расположенные в каталоге /etc/sv/, не выполняются, пока ссылки на них не будут размещены в каталоге /etc/service/.

Как только вы сделаете ln -s /etc/sv/<название сервиса> /etc/service/<название сервиса>, сервис runsvdir увидит новый сервис, и запустит его. Более того, в случае остановки сервиса он будет автоматически перезапущен. Это даёт гораздо более быструю реакцию на остановку сервиса по сравнению с использованием сервисов мониторинга (god или monit).

Ротирование логов


При использовании svlogd логи размещаются в папке, которую Вы указали при её запуске. При этом текущий лог находится в файле current, и периодически выполняется ротирование логов в этой папке.

Управление


Запускать, останавливать, перезапускать сервисы можно с помощью команды sv (start|stop|restart...) <название сервиса>.

Кроме того, при запуске сервиса появится каталог /etc/service/<название сервиса>/supervise, в котором будут расположены очень полезные файлы и потоки:
  • pid — идентификатор процесса Unix;
  • stat — человеко-читаемое состояние сервиса
  • status — машинно-читаемое состояние процесса
  • control — поток управления
  • и так далее...

Можно отметить, что для остановки или запуска процесса достаточно открыть поток control на запись, и отправить туда символ d (от down) или u (от up) соответственно.

В стиле init.d

Нет ничего проще, чем поддержать управление в стиле init.d.

Просто делаем ln -s /usr/bin/sv /etc/init.d/<название сервиса>. sv поймёт, что его вызвали в стиле init.d, и готов будет принимать команды вида /etc/init.d/<название сервиса> start etc. Совсем немного магии, правда?

Настройка сервисов


В комплекте с runit поставляется утилита chpst, которая позволяет выполнять сервисы с дополнительной настройкой (ограничивать размер памяти, запускать из под определенного пользователя, с другим уровнем nice и т.д.).

Резюме


runit оказался настолько удобен и надёжен для организации своих сервисов, что мы стараемcя переводить все наши демоны под runit, заодно отказываясь от различного геморроя в виде пакетов демонизации а ля daemons gem. Также на части машин мы избавились от Monit (где требовался лишь мониторинг процессов).

Крайне рекомендую к прочтению комментарий от powerman, а также статью про Web-интерфейс к runit.
Акжан @akzhan
карма
25,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Администрирование

Комментарии (54)

  • 0
    Спасибо! Похоже полезная вещица, нужно попробовать для своих самоделок.
    • +1
      Забыл ещё дописать про управление в стиле init.d. Дописал, очень удобная магия :)
      • 0
        спасибо большое… завтра-же буду экспериментировать на моей железяки…
  • 0
    /о пользе пробелов/

    Прочит название как r-unit, думал: юнит-тестирование добралось до демонов…
    • 0
      Поскольку с runit демонами становятся обычные процессы, то их отладка становится таким же простым делом, как и для остальных недемонических процессов.

      и никто не мешает писать юнит-тесты вне зависимости от природы программного продукта :)
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    С upstart мирно соседствует? У нас в перемешку debian и ubuntu server, поэтому сейчас опакечиваю в стандартные init скрипты. А так можно было бы про runit задуматься.
  • 0
    Не ради холиварчика, а ради объективности :) Проверил в репозитариях ContOS, нет runit. Что подразумевается под большинством?
    • 0
      Например, Debian Lenny, MacOS X, FreeBSD, OpenBSD, Fedora.

      CentOS сейчас не использую, так что даже не знал, что его там нет.
      • 0
        Сейчас проверил, в народно любимой ubuntu есть.
  • 0
    очень похоже на daemontools

    cr.yp.to/daemontools.html
  • 0
    Акжан, а как насчет например reload'a типа nginx/apache — сначала тестим конфиг, потом, если всё ок — релоад? можно/нужно отдельные скрипты типа reload/restart/whatever класть?
    • +1
      У nginx есть уникальная фича обновления/рестарта сервиса без обрыва текущих соединений — к сожалению, с runit она не совместима.

      Что касается простых вещей типа проверки синтаксиса конфига перед рестартом сервиса — это должно делаться без проблем т.к. runit позволяет установить юзерские скрипты-хуки на отправку сервису конкретных команд/сигналов. Так что вы можете написать скрипт в пару строк, который перехватит отправку сервису команды t(erm), проверит синтаксис конфига и либо пропустит команду t(erm), либо нет. Впрочем, лично я думаю, что это лишнее: если админ допускает синтаксические ошибки при редактировании конфига веб-сервера, то лучше всего этого админа не допускать до продакшн серверов, чем писать такие хуки.
      • 0
        powerman ответил полноценно.

        runit знает о сигналах hup, usr1 etc. и позволяет управлять с их помощью.

        но, касательно nginx, runit не позволяет работать с помощью сигнала WINCH.
  • 0
    Спасибо, пойду соберу rpm-ку для CentOS :)
    • 0
      надеюсь, попадёт в официальную репу :)
  • +20
    Было бы неплохо упомянуть, что пакет runit это развитие (форк) DJBшного пакета daemontools. Софт DJB отличается надёжностью и простотой, но DJB очень не любит добавлять ненужные лично ему фичи — дабы не усложнять и не плодить баги. Пакет runit разрабатывается с учётом принципов DJB, автор тоже крайне неохотно добавляет новые фичи и стремится сохранить простоту кода, но всё-таки фич там больше и пользоваться runit удобнее, чем daemontools.

    Стабильность runit, в принципе, не хуже, чем у daemontools — фактически я знаю только про один баг, который проявляется буквально у нескольких пользователей (включая меня, к сожалению), и который много лет не могут поймать (автору runit этот баг повторить не удаётся). Впрочем, для этого бага есть workaround, так что в результате всё работает много лет без нареканий.

    Было бы неплохо упомянуть, что runit состоит из нескольких независимых частей: процесс N1 (т.е. замена стандартному /sbin/init), супервизор сервисов (который описан в статей) и утилита для управления логами. И можно пользоваться как всеми тремя составляющими, так и отдельно любой из них.

    Мы много лет используем runit и для загрузки систем (вместо стандартного /sbin/init) и для запуска всех сервисов (вместо скриптов в /etc/init.d/). Для Gentoo пакет с runit, с примерами скриптов для загрузки системы и пакеты со скриптами для типовых сервисов доступны в моём оверлее для portage.

    Так же мы используем супервизор сервисов из runit для запуска и управления всеми сервисами необходимыми для наших веб-проектов, при этом и супервизор и сервисы запускаются под обычным юзерским аккаунтом.

    В статье не упомянуто одно из основных достоинств runit — он не использует .pid-файлы для контроля сервисов, т.к. это не атомарно и не надёжно. Вместо этого каждый сервис контролируется отдельным процессом-родителем, который в случае креша сервиса гарантированно и моментально получит SIGCHLD и перезапустит сервис.

    Что касается каталогов /etc/sv/ и /etc/service/ — насколько я помню официальную позицию автора runit, рекомендуется использовать немного другие каталоги. Но вообще пути к каталогам нигде не прошиты, указываются параметром и можно выбирать их по своему вкусу — например, у меня это /service/ и /var/service/.

    Что касается «демонизирования», то в статье это описано некорректно. Во-первых runit ничего не демонизирует (процесс демонизации несколько шире чем просто запуск процесса в фоне). Во-вторых runit не требует того, чтобы сервисы не демонизировали себя, в частности не отцеплялись от STDIN/OUT/ERR — он требует только того, чтобы сервисы не форкались в фоновый процесс. Логи сервисы не обязаны выводить на STDOUT/ERR, хотя это предпочтительный вариант. Впрочем, даже если сервисы выводят логи в файлы самостоятельно (как apache и mysql, к примеру), то это не мешает на месте файлов access_log, etc. разместить FIFO-шки, из которых будут читать svlogd-сервисы и выводить логи в традиционном для runit формате (у нас всё работает именно так).
    • 0
      Спасибо за столь хороший комментарий.
  • –1
    Хорошая статья. Спасибо.
  • 0
    Что там с демонизацией? Что то типа tcpserv есть? Если да то как работает — форк на каждый запрос?
    • 0
      Демонизации (в чистом виде) нет.

      Подробнее в комменте от poweman выше.
    • 0
      Если я правильно догадался, что такое tcpserv, то такая утилита есть в DJBшном пакете ucspi-tcp, называется tcpserver.
      • 0
        ну да
        кстати, чем runit превосходит набор DJB?
  • 0
    runit c вебинтерфесом это supervisord.org/ для серверных ферм гораздо удобнее за счет управления через xml-rpc
    • 0
      Никто не мешает использовать REST-сигналы с runit-man.

      решения наподобие supervisord обладают своими преимуществами и недостатками.

      очень долго их расписывать. В общем случае нужна как система мониторинга локально на машине (runit), так и удалённая (например, cacti/nagios).
      • 0
        где написано что что то мешает?

        зачем использовать runit + нашлепку сбоку на ruby если можно поставить supervisord который все умеет сам без постороенней помощи. По возможностям они абсолютно идентичны. runit хорошь там где мало ресурсов в embedded или на vps, но он не предназначен для распределенного управления.

        runit это не мониторинг, это супервайзер для процессов.

        • 0
          runit — железобетонный супервайзер, вы правы.

          для полноты картины, использует ли supervisorctl SIG_CHILD?
          • 0
            вы хотите чтобы вам документацию пересказали?
          • 0
            Использует.
  • 0
    Коллеги!
    А что я делаю не так:

    $ cat /etc/sv/spawn-fcgi/run
    
    #!/bin/sh
    exec 2>&1
    PHP_FCGI_CHILDREN=5 \
    PHP_FCGI_MAX_REQUESTS=1000 \
    exec /usr/bin/spawn-fcgi -a 127.0.0.1 -p 9000 -u www-data -g www-data -n -- /usr/bin/php5-cgi
    


    Запускаем:

    # sv up spawn-fcgi
    


    Проверяем:
    # sv status spawn-fcgi
    run: spawn-fcgi: (pid 435) 1s
    # sv status spawn-fcgi
    run: spawn-fcgi: (pid 446) 1s
    # sv status spawn-fcgi
    run: spawn-fcgi: (pid 450) 1s
    # sv status spawn-fcgi
    run: spawn-fcgi: (pid 454) 1s
    


    Где я ошибся?
    • 0
      попробуйте оставновить сервис, перейти в каталог сервиса и выполнить ./run
      Всё увидите.

      Навскидку всё в порядке, опция -n прописана.
      • 0
        Спасибо.
        Я сам дурак, забыл chmod +x на run сделать.

        P.S. спасибо за статью.
        • 0
          на досуге попробуйте поставить ruby и rubygems, сделать
          gem install thin runit-man
          runit-man -p 14000 -r

          и потом посмотреть на страницу localhost:14000
          • 0
            Еще вчера.
            Спасибо ;)
  • 0
    А что делать с сервисами, не умеющими не отвязываться от консоли?
    zabbix-server например.
    • 0
      Вообще-то для запуска сервисов runit отвязка от консоли не нужна и даже вредна.

      Я наоборот, убираю всякие опции демонизации. Мне удобнее, чтобы ошибки сыпались в stdout/stderr, их оттуда подхватит svlogd.
      • 0
        Так о том и речь — он НЕ умеет НЕ отвязываться.
        Он сразу после запуска форкается и уходит в бэкграунд.
        Runit его тут же теряет есессна.
        • 0
          подстава :) в таком случае сам процесс в runit не подсунуть, к сожалению.

          либо оставить как есть, либо писать оберточный процесс (daemon controller), либо писать feature request авторам zabbix.

          всё-таки у них должна быть фича запускать сервер в фореграунде, хотя бы для отладки.
  • 0
    orion www # /etc/init.d/unicorn start
    fail: unicorn: runsv not running

    Если же перед этим сделать
    runsv /var/service/unicorn
    То всё ок, только это же не выход
    • +1
      у вас, видимо, не запущен супервизор runsvdir.
      • 0
        Возможно я что-то неверно делаю, но запуск runsvdir запускает мне всех моих демонов
        • +1
          так и должно быть.

          /etc/sv — все сервисы
          /etc/service — симлинки на активные.
          • 0
            Видимо я что-то не улавливаю.
            Ещё раз: что мне надо сделать, чтобы при загрузке демоны не поднимались, но /etc/init.d/демон start работал без проблем?
            • 0
              Боюсь, это выбивается из обычного сценария.

              В вашем случае init.d-скрипт должен активировать сервис в случае его неактивности и т.д… То есть писать руками.
              • 0
                Печаль, понравилась идея использовать runit, как дополнение к гентушному openrc, но видимо не судьба(
        • +1
          Всегда можно для активного сервиса сделать
          sv stop service-name.

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