В этой заметке я расскажу о том, как настроить сервис Linux для автоматического запуска демона после сбоя или перезагрузки. В качестве примера я буду использовать Nginx и PHP но вы можете этот способ для любых приложений.
Уже прошло достаточно много времени с того момента, как большинство популярных дистрибутивов Linux перешли на системный менеджер systemd
. Тем не менее, до сих пор старая система инициализации SysV продолжает параллельно функционировать на ряду с systemd
. И как и раньше, большинство пакетов после установки добавляют стартовый скрипт в каталог init.d
.
Не буду вдаваться в подробности про механизмы параллелизации systemd
и скорость загрузку системы. Это все хорошо и прекрасно. Но для меня главный аргумент в ползу перехода на systemd
— это наличие встроенных функций отслеживания и контроля состояния сервисов. Что бы было понятнее, давайте представим следующую ситуацию.
Для примера мы установили OpenVPN, для которого по умолчанию используется механизм запуска System V. Во время установки пакета в каталог /etc/init.d
будет скопирован скрипт инициализации, который будет отвечать за автоматический запуск приложения после перезагрузки. Если в один прекрасный день OpenVPN упадет, без дополнительных настроек, нужно будет каждый раз запускать этот процесс вручную.
Теперь возьмем ситуацию, когда для запуск сервиса выполнен через systemd
. Если произойдет крэш или даже если вы захотите специально убить процесс, то systemd
автоматически это обнаружит и повторно запустит процесс. При этом systemd
обратно совместим с командами System V и сценариями инициализации.
А теперь давайте рассмотрим, как быстро добавить сервис в systemd
. Демон systemd
запускает сервисы описанные в его конфигурации. Конфигурация состоит из файлов, которые называют юнитами. Для юнитов созданных вручную используется каталог:
/etc/systemd/system/
В простом варианте юнит состоит из трех секции: [Unit]
, [Service]
, [Install]
.
Секция [Unit]
Описание юнита:
Description=MyUnit
Далее указываем порядок загрузки, после какого сервиса systemd
запустить наш юнит:
After=syslog.target After=network.target
Секция [Service]
Задаем тип сервиса:
Type=simple
Используется по умолчанию. Служба будет запущена незамедлительно. Процесс при этом не должен разветвляться. Не используйте этот тип, если другие службы зависят от очередности при запуске данной службы.
Type=forking
Указывают если служба запускается однократно и процесс разветвляется с завершением родительского процесса.
Расположение pid-файла:
PIDFile=/run/service.pid
Рабочий каталог приложения:
WorkingDirectory=/usr/local/service
Пользователь и группа, под которым будет запускаться сервис:
User=unit Group=unit
Задаем приоритет убийства процесса при нехватке памяти:
OOMScoreAdjust=-100
Минимальное значение -1000 — полный запрет.
Команды запуска, остановки и перезапуска сервиса:
ExecStart=/usr/sbin/service ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID
Таймаут запуска или остановки сервиса:
TimeoutSec=300
Контроль запуска сервиса и автоматический запуск в случае крєша:
Restart=always
Секция [Install]
Уровень запуска сервиса:
WantedBy=multi-user.target
В итоге мы получили следующий юнит:
[Unit] Description=MyUnit After=syslog.target After=network.target [Service] Type=forking PIDFile=/run/service.pid WorkingDirectory=/usr/local/service User=munit Group=unit OOMScoreAdjust=-100 ExecStart=/usr/sbin/service ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID TimeoutSec=300 [Install] WantedBy=multi-user.target
Добавляем юнит в каталог:
nano /etc/systemd/system/unit_name
Включаем, запускаем и смотрим статус юнита:
systemctl enable unit_name systemctl start unit_name systemctl -l status unit_name systemctl daemon-reload
А теперь привожу примеры работающих юнитов.
Юнит systemd
для запуска Nginx:
[Unit] Description=The NGINX HTTP and reverse proxy server After=syslog.target network.target remote-fs.target nss-lookup.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t ExecStart=/usr/sbin/nginx ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target
Юнит systemd
для запуска php-fpm
:
[Unit] Description=The PHP FastCGI Process Manager After=syslog.target network.target [Service] Type=simple PIDFile=/usr/local/php-fpm/var/run/php-fpm.pid ExecStart=/usr/local/php-fpm/sbin/php-fpm --nodaemonize --fpm-config /usr/local$ ExecReload=/bin/kill -USR2 $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target