Unit for tg bot: различия между версиями
Admin (обсуждение | вклад) Нет описания правки |
Artem (обсуждение | вклад) Нет описания правки Метки: с мобильного устройства из мобильной версии |
||
| (не показаны 4 промежуточные версии 2 участников) | |||
| Строка 1: | Строка 1: | ||
= | = Запуск Python-скрипта как службы systemd = | ||
В Linux Python-скрипт можно запустить как системную службу с помощью ‘’‘systemd’’’ . | |||
Это удобно для Telegram-ботов, веб-сервисов и других приложений, которые должны: | |||
* автоматически запускаться вместе с сервером; | |||
* работать в фоновом режиме; | |||
* автоматически перезапускаться после ошибки; | |||
* управляться стандартными командами systemctl; | |||
* сохранять журнал работы в journalctl. | |||
В этой статье рассмотрим два варианта запуска Python-приложения на примере Telegram-бота ‘’‘noProdaction’’’. | |||
TOC | |||
== Способ №1 — запуск через отдельный shell-скрипт == | |||
В этом варианте systemd запускает вспомогательный shell-скрипт, который, в свою очередь, запускает Python-приложение. | |||
Схема запуска: | |||
<pre> | |||
systemd | |||
│ | |||
▼ | |||
noProdaction.sh | |||
│ | |||
▼ | |||
python3 | |||
│ | |||
▼ | |||
main.py | |||
</pre> | |||
=== Создание скрипта запуска === | |||
Создаём каталог для скрипта запуска, если его ещё нет: | |||
<syntaxhighlight lang="bash"> | |||
mkdir -p /opt/Python/Telegram/start | |||
</syntaxhighlight> | |||
Создаём файл: | |||
<syntaxhighlight lang="bash"> | |||
nano /opt/Python/Telegram/start/noProdaction.sh | |||
</syntaxhighlight> | |||
Добавляем: | |||
<syntaxhighlight lang="bash"> | |||
#!/bin/bash | |||
exec /usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py | |||
Сохраняем файл: | |||
<pre> | |||
Ctrl + O | |||
Enter | |||
Ctrl + X | |||
</pre> | |||
Делаем его исполняемым: | |||
<syntaxhighlight lang="bash"> | |||
chmod +x /opt/Python/Telegram/start/noProdaction.sh | |||
</syntaxhighlight> | |||
{{Note|Использование exec позволяет заменить процесс shell непосредственно процессом Python. Благодаря этому systemd корректнее отслеживает PID приложения и управляет его завершением.}} | |||
=== Создание systemd unit === | |||
Создаём unit-файл: | |||
<syntaxhighlight lang="bash"> | |||
nano /etc/systemd/system/noprodaction.service | |||
</syntaxhighlight> | |||
Добавляем: | |||
<syntaxhighlight lang="ini"> | |||
[Unit] | |||
Description=Telegram bot noProdaction | |||
After=network-online.target | |||
Wants=network-online.target | |||
[Service] | |||
Type=simple | |||
User=root | |||
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1 | |||
ExecStart=/opt/Python/Telegram/start/noProdaction.sh | |||
Restart=on-failure | |||
RestartSec=5 | |||
NoNewPrivileges=true | |||
PrivateDevices=true | |||
ProtectSystem=full | |||
[Install] | |||
WantedBy=multi-user.target | |||
Сохраняем файл: | |||
<pre> | |||
Ctrl + O | |||
Enter | |||
Ctrl + X | |||
</pre> | |||
=== Активация службы === | |||
После создания или изменения unit-файла необходимо перечитать конфигурацию systemd: | |||
<syntaxhighlight lang="bash"> | |||
systemctl daemon-reload | |||
</syntaxhighlight> | |||
Добавляем службу в автозагрузку: | |||
<syntaxhighlight lang="bash"> | |||
systemctl enable noprodaction.service | |||
</syntaxhighlight> | |||
Запускаем: | |||
<syntaxhighlight lang="bash"> | |||
systemctl start noprodaction.service | |||
</syntaxhighlight> | |||
Можно выполнить обе команды сразу: | |||
<syntaxhighlight lang="bash"> | |||
systemctl enable --now noprodaction.service | |||
</syntaxhighlight> | |||
=== Проверка работы === | |||
Проверяем состояние: | |||
<syntaxhighlight lang="bash"> | |||
systemctl status noprodaction.service | |||
</syntaxhighlight> | |||
При нормальной работе должна присутствовать строка: | |||
<pre> | |||
Active: active (running) | |||
</pre> | |||
Например: | |||
<pre> | |||
● noprodaction.service - Telegram bot noProdaction | |||
Loaded: loaded (/etc/systemd/system/noprodaction.service; enabled) | |||
Active: active (running) | |||
Main PID: 173 (python3.11) | |||
Tasks: 2 | |||
Memory: 34.1M | |||
CPU: 1.766s | |||
</pre> | |||
== Способ №2 — запуск Python напрямую из systemd == | |||
{{Note|’’‘Рекомендуемый вариант.’’’ Если для запуска приложения не требуется выполнять дополнительные команды, создавать отдельный .sh-файл нет необходимости. Python можно запускать непосредственно из systemd.}} | |||
Схема становится проще: | |||
<pre> | |||
systemd | |||
│ | |||
▼ | |||
python3 | |||
│ | |||
▼ | |||
main.py | |||
</pre> | |||
Создаём unit-файл: | |||
<syntaxhighlight lang="bash"> | |||
nano /etc/systemd/system/noprodaction.service | |||
</syntaxhighlight> | |||
Добавляем: | |||
<syntaxhighlight lang="ini"> | |||
[Unit] | |||
Description=Telegram bot noProdaction | |||
After=network-online.target | |||
Wants=network-online.target | |||
[Service] | |||
Type=simple | |||
User=root | |||
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1 | |||
ExecStart=/usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py | |||
Restart=on-failure | |||
RestartSec=5 | |||
NoNewPrivileges=true | |||
PrivateDevices=true | |||
ProtectSystem=full | |||
[Install] | |||
WantedBy=multi-user.target | |||
После создания файла выполняем: | |||
<syntaxhighlight lang="bash"> | |||
systemctl daemon-reload | |||
systemctl enable --now noprodaction.service | |||
</syntaxhighlight> | |||
Проверяем: | |||
<syntaxhighlight lang="bash"> | |||
systemctl status noprodaction.service | |||
</syntaxhighlight> | |||
== Управление службой == | |||
После создания unit-файла ботом можно управлять стандартными командами systemd. | |||
{| class=“wikitable” | |||
! Действие | |||
! Команда | |||
Проверить состояние | |||
systemctl status noprodaction | |||
- | |||
Запустить | |||
systemctl start noprodaction | |||
- | |||
Остановить | |||
systemctl stop noprodaction | |||
- | |||
Перезапустить | |||
systemctl restart noprodaction | |||
- | |||
Добавить в автозагрузку | |||
systemctl enable noprodaction | |||
- | |||
Убрать из автозагрузки | |||
systemctl disable noprodaction | |||
} | |||
== Просмотр логов == | |||
Одно из преимуществ запуска через systemd — вывод Python-приложения автоматически попадает в системный журнал. | |||
Посмотреть последние записи: | |||
<syntaxhighlight lang="bash"> | |||
journalctl -u noprodaction.service | |||
</syntaxhighlight> | |||
Последние 100 строк: | |||
<syntaxhighlight lang="bash"> | |||
journalctl -u noprodaction.service -n 100 | |||
</syntaxhighlight> | |||
Следить за журналом в реальном времени: | |||
<syntaxhighlight lang="bash"> | |||
journalctl -u noprodaction.service -f | |||
</syntaxhighlight> | |||
Выйти из режима просмотра: | |||
<pre> | |||
Ctrl + C | |||
</pre> | |||
Посмотреть журнал только с момента последней загрузки сервера: | |||
<syntaxhighlight lang="bash"> | |||
journalctl -u noprodaction.service -b | |||
</syntaxhighlight> | |||
== После изменения Python-кода == | |||
Если был изменён только код main.py или других файлов приложения, выполнять daemon-reload не требуется. | |||
Достаточно перезапустить приложение: | |||
<syntaxhighlight lang="bash"> | |||
systemctl restart noprodaction | |||
</syntaxhighlight> | |||
Если же был изменён сам файл: | |||
<pre> | |||
/etc/systemd/system/noprodaction.service | |||
</pre> | |||
необходимо выполнить: | |||
<syntaxhighlight lang="bash"> | |||
systemctl daemon-reload | |||
systemctl restart noprodaction | |||
</syntaxhighlight> | |||
== Автоматический перезапуск == | |||
В нашем unit-файле используются параметры: | |||
<syntaxhighlight lang="ini"> | |||
Restart=on-failure | |||
RestartSec=5 | |||
</syntaxhighlight> | |||
Это означает, что если Python-процесс аварийно завершится, systemd подождёт 5 секунд и попробует запустить его снова. | |||
Проверить количество перезапусков можно командой: | |||
<syntaxhighlight lang="bash"> | |||
systemctl show noprodaction.service -p NRestarts | |||
</syntaxhighlight> | |||
== Проверка пути к Python == | |||
Путь к Python может отличаться в зависимости от системы. | |||
Проверить его можно командой: | |||
<syntaxhighlight lang="bash"> | |||
which python3 | |||
</syntaxhighlight> | |||
Например: | |||
<pre> | |||
/usr/bin/python3 | |||
</pre> | |||
Версию Python: | |||
<syntaxhighlight lang="bash"> | |||
python3 --version | |||
</syntaxhighlight> | |||
Если конкретная версия Python не требуется, в unit-файле можно использовать: | |||
<syntaxhighlight lang="ini"> | |||
ExecStart=/usr/bin/python3 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py | |||
</syntaxhighlight> | |||
== Запуск через Python Virtual Environment == | |||
Если проект использует собственное виртуальное окружение Python, рекомендуется запускать Python непосредственно из него. | |||
Например, если виртуальное окружение находится здесь: | |||
<pre> | |||
/opt/Python/Telegram/noProdaction/venv/ | |||
</pre> | |||
то ExecStart будет выглядеть так: | |||
<syntaxhighlight lang="ini"> | |||
ExecStart=/opt/Python/Telegram/noProdaction/venv/bin/python /opt/Python/Telegram/noProdaction/noprodaction-1/main.py | |||
</syntaxhighlight> | |||
Активировать venv командой source внутри systemd не требуется. | |||
== Рекомендуемый unit-файл == | |||
Для обычного Python-приложения итоговый вариант может выглядеть следующим образом: | |||
<syntaxhighlight lang="ini"> | |||
[Unit] | |||
Description=Telegram bot noProdaction | |||
After=network-online.target | |||
Wants=network-online.target | |||
[Service] | |||
Type=simple | |||
User=root | |||
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1 | |||
ExecStart=/usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py | |||
Restart=on-failure | |||
RestartSec=5 | |||
NoNewPrivileges=true | |||
PrivateDevices=true | |||
ProtectSystem=full | |||
[Install] | |||
WantedBy=multi-user.target | |||
После создания: | |||
<syntaxhighlight lang="bash"> | |||
systemctl daemon-reload | |||
systemctl enable --now noprodaction.service | |||
</syntaxhighlight> | |||
Проверяем: | |||
<syntaxhighlight lang="bash"> | |||
systemctl status noprodaction.service | |||
</syntaxhighlight> | |||
и журнал: | |||
<syntaxhighlight lang="bash"> | |||
journalctl -u noprodaction.service -f | |||
</syntaxhighlight> | |||
== Примечание по безопасности == | |||
В примерах выше служба запускается от пользователя: | |||
<syntaxhighlight lang="ini"> | |||
User=root | |||
</syntaxhighlight> | |||
Для собственного сервера это работает, однако большинству Python-приложений права root не нужны. | |||
Более безопасный вариант — создать отдельного системного пользователя для приложения и запускать службу от его имени. | |||
Например: | |||
<syntaxhighlight lang="bash"> | |||
useradd --system --home /opt/Python/Telegram/noProdaction --shell /usr/sbin/nologin noprodaction | |||
</syntaxhighlight> | |||
После этого необходимо выдать пользователю права на необходимые файлы приложения и заменить в unit-файле: | |||
<syntaxhighlight lang="ini"> | |||
User=root | |||
</syntaxhighlight> | |||
на: | |||
<syntaxhighlight lang="ini"> | |||
User=noprodaction | |||
</syntaxhighlight> | |||
{{Warning|Не храните токены Telegram-бота, API-ключи, пароли баз данных и другие секреты непосредственно в публичном unit-файле или исходном коде проекта. Для секретов лучше использовать отдельный файл окружения с ограниченными правами доступа.}} | |||
== Итог == | |||
Для простого Python-приложения рекомендуется использовать ‘’‘Способ №2’’’: | |||
<pre> | |||
Загрузка Linux | |||
│ | |||
▼ | |||
systemd | |||
│ | |||
▼ | |||
noprodaction.service | |||
│ | |||
▼ | |||
Python | |||
│ | |||
▼ | |||
main.py | |||
│ | |||
▼ | |||
Telegram Bot | |||
</pre> | |||
После этого приложение автоматически запускается вместе с системой, работает в фоне и при аварийном завершении автоматически запускается снова. | |||