Изо всех щелей рассказывают о том, какой systemd хороший. На эти рассказы даже купились в Debian, устраивали голосования одно за другим вплоть до достижения "нужного" исхода. Решение пропихнули и в Jessie теперь systemd идёт по умолчанию. Только вот в Jessie service-файлов кот наплакал и большей частью всё происходит по старинке - через те же скрипты /etc/init.d/, только теперь запускает их процесс с другим именем. Непонятно, то ли происходит саботаж этого решения, то ли на самом деле не так уж важны эти фишки systemd. А вы думали только в России бывает такое головотяпство?
Скрипт /etc/init.d/uwsgi кроме команды типа start/stop/restart опционально может принимать ещё имя экземпляра, так что с помощью этого скрипта можно было легко перезапускать отдельные экземпляры uwsgi, обслуживающие разные приложения. Теперь при попытке воспользоваться этим скриптом происходит перехват управления, в результате чего этот скрипт выполняется через systemctl. systemctl о дополнительном аргументе ничего не знает, поэтому указать нужный экземпляр uwsgi не представляется возможным. Перехват происходит через файл-хук /lib/lsb/init-functions.d/40-systemd, который используется в файле /lib/lsb/init-functions, который в свою очередь используется во всех скриптах /etc/init.d/ в Debian.
Само собой напрашивалось решение с многоэкземплярным service-файлом, который вызывался бы примерно так:
# systemctl start uwsgi@redmine.service
Но тут я вспомнил о том, что в Jessie поставляется новый uwsgi, в котором поддерживается режим Emperor. Emperor - это отдельный процесс uwsgi, который умеет заглядывать в указанный каталог и искать там файлы конфигурации экземпляров uwsgi. При появлении нового файла конфигурации он умеет самостоятельно порождать новые процессы master, которые в свою очередь порождают процессы worker. Соответственно, при пропадании файла конфигурации Emperor корректно завершает master-процесс, соответствующий пропавшему файлу конфигурации. Плюс к тому, он умеет следить за master-процессами, порождая их, если они вдруг неожиданно завершились.
Поиски документации привели меня сюда: uwsgi - systemd. В ходе экспериментов получилось рабочее решение, которым и спешу поделиться.
Для начала создадим service-файл /etc/systemd/system/uwsgi.service:
[Unit] Description=uWSGI Emperor After=syslog.target [Service] ExecStart=/usr/bin/uwsgi --ini /etc/uwsgi/emperor.ini Restart=always KillSignal=SIGQUIT Type=notify StandardError=syslog NotifyAccess=all [Install] WantedBy=multi-user.target
Теперь создаём файл /etc/uwsgi/emperor.ini, который будет содержать конфигурацию "императора":
[uwsgi] emperor = /etc/uwsgi/apps-enabled/ vassals-inherit = /etc/uwsgi/vassal-default.ini
Теперь создаём файл с настройками по умолчанию для "вассалов". За основу возьмём файл /usr/share/uwsgi/conf/default.ini, который упоминался в файле /etc/default/uwsgi. Пути к файлам придётся изменить так, чтобы для создания любого из файлов не нужно было создавать соответствующий каталог - файл взятый за основу этим грешит, но в нём это не является проблемой, т.к. файл инициализации может создавать необходимые каталоги сам. Доведя файл конфигурации вассала до состояния, пригодного для использования, получим файл /etc/uwsgi/vassal-default.ini:
[uwsgi] autoload = true master = true workers = 2 no-orphans = true pidfile = /run/uwsgi/%N.pid socket = /run/uwsgi/%N.socket chmod-socket = 660 logto = /var/log/uwsgi/%N.log log-date = true uid = www-data gid = www-data
Есть ещё один странный момент. Чтобы экземпляры заработали, у имён плагинов нужно убрать префикс uwsgi_. Например, имя плагина плагина uwsgi_rack_ruby21 нужно сократить до rack_ruby21.
Чтобы при перезагрузке компьютера создавался каталог /run/uwsgi, создадим файл /etc/tmpfiles.d/uwsgi.conf со следующей строчкой:
d /run/uwsgi 0750 www-data www-data -
На всякий случай приведу команду, при помощи которой можно создать все каталоги, создаваемые в процессе загрузки системы:
# systemd-tmpfiles --create
Поскольку пути к сокетам поменяются, нужно подготовить пути к новым сокетам в конфигурации nginx.
Теперь останавливаем uwsgi, запущенный скриптом /etc/init.d/uwsgi, включаем использование service-файла и запускаем uwsgi уже с его помощью:
# systemctl stop uwsgi.service # systemctl enable uwsgi.service # systemctl start uwsgi.service
Чтобы nginx обращался к новым сокетам, размещающимся прямо в каталоге /run/uwsgi, перезапустим и его:
# systemctl restart nginx.service
И как же теперь перезагрузить/перезапустить экземпляр uwsgi? К сожалению, это не так наглядно, как со скриптом /etc/init.d/uwsgi. Для перезагрузки конфигурации используется команда с PID-файлом экземпляра:
# uwsgi --reload /run/uwsgi/redmine.pid
Перезапуск делается через остановку экземпляра, а systemd автоматически запустит его снова:
# uwsgi --stop /run/uwsgi/redmine.pid
Чтобы остановить экземпляр, нужно удалить ссылку из каталога /etc/uwsgi/apps-enabled/:
# rm /etc/uwsgi/apps-enabled/redmine.ini
Чтобы снова запустить экземпляр, нужно снова создать ссылку в каталоге /etc/uwsgi/apps-enabled/:
# ln -s /etc/uwsgi/apps-available/redmine.ini /etc/uwsgi/apps-enabled/redmine.ini
Посмотреть список запущенных процессов можно при помощи systemctl:
$ systemctl status uwsgi.service
На этом всё. Если у вас есть идеи, как сделать перезапуск экземпляров более наглядным, например при помощи многоэкземплярного service-файла, прошу делиться предложениями.