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

Нет описания правки
Метки: с мобильного устройства из мобильной версии
Нет описания правки
Метки: с мобильного устройства из мобильной версии
 
(не показаны 2 промежуточные версии этого же участника)
Строка 1: Строка 1:
== '''Создаем Unit для tg bot''' ==
= Запуск Python-скрипта как службы systemd =


=== '''Способ №1:''' ===
В Linux Python-скрипт можно запустить как системную службу с помощью ‘’‘systemd’’’ .


Это удобно для Telegram-ботов, веб-сервисов и других приложений, которые должны:
Создаем исполняемый фаил '''noProdaction.sh''' и в нем вписываем что то типо:
   
    #!/bin/bash<br><br>
    /usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py


Далее создаем  с помощью нашего любимого редактора '''nano''' по пути /'''etc/systemd/system/''' фаил '''noprodaction.service''' 
* автоматически запускаться вместе с сервером;
* работать в фоновом режиме;
* автоматически перезапускаться после ошибки;
* управляться стандартными командами systemctl;
* сохранять журнал работы в journalctl.


    nano /etc/systemd/system/noprodaction.service
В этой статье рассмотрим два варианта запуска Python-приложения на примере Telegram-бота ‘’‘noProdaction’’’.


И вписываем что то типо такого:
TOC


    [Unit]
== Способ №1 — запуск через отдельный shell-скрипт ==
    Description=telegam bot OmArtVal
    After=network.target<br>
    [Service]
    User=root
    Nice=1
    KillMode=process
    SuccessExitStatus=0 1
    ProtectHome=true
    ProtectSystem=full
    PrivateDevices=true
    NoNewPrivileges=true
    WorkingDirectory=/opt/Python/Telegram/noProdaction
    ExecStart=/opt/Python/Telegram/start/noProdaction.sh
    Restart=always<br>
    [Install]
    WantedBy=multi-user.target


Закрываем редактор с сохранением изменений '''CTRL+O''' и '''CTRL+X'''
В этом варианте systemd запускает вспомогательный shell-скрипт, который, в свою очередь, запускает Python-приложение.


Перезагружаем демона:
Схема запуска:


    systemctl daemon-reload
<pre>
systemd
  │
  ▼
noProdaction.sh
  │
  ▼
python3
  │
  ▼
main.py
</pre>


И стартуем его:
=== Создание скрипта запуска ===


    systemctl start noprodaction.service
Создаём каталог для скрипта запуска, если его ещё нет:


И все! Наш сервис должен работать! Проверить это можно командой
<syntaxhighlight lang="bash">
mkdir -p /opt/Python/Telegram/start
</syntaxhighlight>


    systemctl status noprodaction.service
Создаём файл:


Вывод должен быть таким:
<syntaxhighlight lang="bash">
nano /opt/Python/Telegram/start/noProdaction.sh
</syntaxhighlight>


    root@python:~# systemctl status noprodaction.service
Добавляем:
    * noprodaction.service - telegam bot noProdaction
        Loaded: loaded (/etc/systemd/system/noprodaction.service; enabled; vendor preset: enabled)
        Active: active (running) since Tue 2023-11-14 11:44:32 MSK; 3h 14min ago
      Main PID: 173 (python3.11)
          Tasks: 2 (limit: 96529)
        Memory: 34.1M
            CPU: 1.766s
        CGroup: /system.slice/noprodaction.service
                `-173 /usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py<br>
    Nov 14 11:44:32 python systemd[1]: Started telegam bot noProdaction.


и у нас при старте сервера вудет работать скрипт.
<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>
 
После этого приложение автоматически запускается вместе с системой, работает в фоне и при аварийном завершении автоматически запускается снова.