Как написать пользовательский сервис systemctl Linux для сценариев Python с использованием virtualenv и файла .env
Вы можете обнаружить, что у вас есть файл на языке Python, который работает в бесконечном цикле (вспомните серверы и потоковые сокеты). В таких случаях вам понадобится служба, которая будет поддерживать этот файл в рабочем состоянии. Чтобы не нужно было вручную запускать его каждый раз, когда перезагружается машина или заканчивается SSH-сессия. Я приведу пример того, как это сделать на машине Pop_OS!, но это должно работать на всех системах на базе Ubuntu (и Debian).
Шаг 1: Подготовка сценария
Мой скрипт находится в каталоге и может быть выполнен следующим образом:
/home/admin/python/.venv/bin/python /home/admin/python/media-telegram-bot/main.py
Ваш вариант будет аналогичным.
Убедитесь, что вы используете абсолютный путь к бину python внутри virtualenv (если он у вас есть). А также абсолютный путь к самому файлу Python. Таким образом, мы устраняем все неоднозначности, возникающие при использовании относительных путей.
Шаг 2: Запись файла блока
В дистрибутивах Linux, использующих систему инициализации systemd, под юнитом понимается любой ресурс или сервис, с которым может работать система. Конфигурационные файлы этих сервисов являются файлами юнитов. Свой мы запишем по пути /etc/system/systemd dir.
Systemd может иметь различные типы ресурсов, определяемые их префиксом. Например, .service, .socket, .device, .mount.
Наш юнит-файл будет выглядеть примерно так:
[Unit]
Description=Media Request Telegram Bot service
After=network.target
[Service]
User=admin
Group=admin
EnvironmentFile=/home/admin/python/media-telegram-bot/.env
ExecStart=/home/admin/python/.venv/bin/python /home/admin/python/media-telegram-bot/main.py
Restart=always
[Install]
WantedBy=multi-user.target
Директивы [Unit], [Service] и [Install] – это Директивы разделов.
[Unit]
Описание= Название и основные функциональные возможности устройства.
After= Перечисленные здесь устройства будут запущены до запуска текущего устройства.
[Service]
User=, Group= Устанавливает пользователя и/или группу UNIX, от имени которых будет выполняться процесс(ы).
EnvironmentFile= Устанавливает переменные окружения в указанном файле для выполняемых процессов. Можно также использовать Environment=, если используются неконфиденциальные переменные окружения, например, loglevel.
ExecStart= Указывает команды, которые будут выполняться при запуске данной службы.
Restart= Указывает, при каких сценариях сервис будет перезапускаться. Может принимать следующие варианты: нет, при успехе, при неудаче, при ненормальном состоянии, при следящей собаке, при прерывании и всегда.
[Install].
Эта директива необходима, когда нужно, чтобы служба была включена d. т.е. автоматически запускалась при загрузке.
Если текущий модуль имеет WantedBy=multi-user.target, то в каталоге /etc/systemd/system будет создан каталог multi-user.target.wants (если он еще не существует) и в нем будет размещена симлинк на текущий модуль. Отключение этого блока удаляет ссылку и устраняет зависимость. Мы сможем убедиться в этом на собственном опыте, когда позже включим этот модуль.
Сохраним файл в каталоге /etc/systemd/system/media_request_yts_telegram_bot.service
Шаг 3: Запуск сервиса
systemctl start media_request_yts_telegram_bot
При необходимости добавьте sudo.
Вы можете посмотреть записи журнала из журнала systemd.
journalctl -u media_request_yts_telegram_bot -e -f
Чтобы остановить работу службы:
systemctl stop media_request_yts_telegram_bot
Шаг 4: Включить службу
Чтобы настроить автоматический запуск службы при загрузке:
systemctl enable media_request_yts_telegram_bot
В результате будет выведено:
Created symlink /etc/systemd/system/multi-user.target.wants/media_request_yts_telegram_bot.service → /etc/systemd/system/media_request_yts_telegram_bot.service.
Таким образом, в каталоге multi-user.target.wants в каталоге /etc/systemd/system размещается симлинк на текущее устройство. Теперь наш сервис будет выдерживать перезагрузки системы.
Заключение:
Мы узнали, как писать файлы unit.service, какие директивы в них содержатся, как заставить их считывать данные из файла .env, как запускать и останавливать службу, как читать журналы из журнала systemd и как включить автозапуск службы при загрузке.