Использование 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.