Unit for tg bot: различия между версиями

Содержимое страницы заменено на «== '''Создаем Unit для tg bot''' ==»
Метки: замена с мобильного устройства из мобильной версии
Нет описания правки
Метки: с мобильного устройства из мобильной версии
 
(не показана 1 промежуточная версия этого же участника)
Строка 1: Строка 1:
== '''Создаем Unit для tg bot''' ==
= Запуск 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>
 
После этого приложение автоматически запускается вместе с системой, работает в фоне и при аварийном завершении автоматически запускается снова.