Скрипт Python как служба Linux
Обновлено: 21.11.2024
» В компьютерных операционных системах на базе Unix init (сокращение от инициализации) — это первый процесс, запускаемый при загрузке компьютерной системы. Init — это процесс-демон, который продолжает работать до тех пор, пока система не будет выключена».
Система инициализации Linux развивалась с течением времени, т. е. вы можете слышать о разных системах, например о sysV, upstart или systemd.
- система V является самой старой из трех упомянутых систем инициализации:
- Debian 6 и более ранние версии
- Ubuntu 9.04 и более ранние версии
- CentOS 5 и более ранние версии
- От Ubuntu 9.10 до Ubuntu 14.10, включая Ubuntu 14.04
- ЦентрОС 6
- Debian 7 и Debian 8
- Убунту 15.04
- ЦентрОС 7
Леннарт Поттеринг и Кей Сиверс начали проект по разработке systemd в 2010 году, а в мае 2011 года Fedora стала первым крупным дистрибутивом Linux, в котором systemd стала системой инициализации по умолчанию. . По состоянию на 2015 год большинство дистрибутивов Linux используют systemd в качестве системы инициализации по умолчанию.
Как указано в приведенном выше определении, init является первым процессом при загрузке, поэтому имеет идентификатор процесса 1. Вы можете проверить используемую систему инициализации различными способами, один из которых — получить ее из процесса с идентификатором 1. :
[nahmed@localhost ~]$ sudo ps 1
PID TTY STAT TIME COMMAND
1 ? Сс 4:08 /usr/lib/systemd/systemd --system --deserialize 17systemd — это демон ОС Linux, который обрабатывает все вызовы системных служб, т. е. запуск, остановку, включение. Включение системной службы «systemctl enable» указывает systemd запускать службу при перезагрузке. Будучи разработчиком Python, вы могли разработать сценарий или приложение Python, предназначенное для непрерывной работы в качестве службы или демона (служба в фоновом режиме), например, сервер RPC, потребитель очереди сообщений, издатель пульса и т. д., зарегистрировав его. как системное обслуживание является хорошей практикой. Вот у меня есть RPC-сервер, написанный на Python, я хочу зарегистрировать его как системную службу, которую обрабатывает systemd, т. е. запускать, останавливать, запускать при загрузке и т. д.
Шаг 1. Создайте файл модуля
После того как у вас будет готов серверный скрипт Python, вам нужно будет создать файл конфигурации (также известный как юнит-файл), который сообщает systemd, что и когда мы хотим от него делать:
Написание службы systemd на Python
Многие дистрибутивы Linux используют systemd для управления системными службами (или демонами), например, для автоматического запуска определенных служб в правильном порядке при загрузке системы.
Написание службы systemd на Python оказывается простым делом, но сложность systemd поначалу может пугать. Это руководство предназначено для того, чтобы вы начали работу.
Если вы чувствуете себя потерянным или нуждаетесь в подробностях, обратитесь к документации systemd, которая довольно обширна. Однако документы распределены по нескольким страницам, и найти то, что вы ищете, не всегда просто. Хорошим местом для поиска конкретной детали systemd является systemd.directives, в котором перечислены все параметры конфигурации, параметры командной строки и т. д., а также ссылки на их документацию.
Помимо этого файла README.md, этот репозиторий содержит базовую реализацию службы Python, состоящую из скрипта Python ( python_demo_service.py ) и файла модуля systemd ( python_demo_service.service ).
Версия systemd, с которой мы будем работать, – 229, поэтому, если вы используете другую версию (см. systemctl --version ), проверьте документацию по systemd, чтобы узнать, что может отличаться.
Системные и пользовательские службы
systemd поддерживает как системные, так и пользовательские службы. Системные службы работают в собственном системном экземпляре systemd и предоставляют функциональные возможности для всей системы и всех пользователей. Пользовательские службы, с другой стороны, запускаются в отдельном экземпляре systemd, привязанном к конкретному пользователю.
Даже если вашей целью является разработка системной службы, рекомендуется начать с пользовательской службы, так как это позволяет вам сосредоточиться на настройке и запуске службы, прежде чем заниматься сложностями настройки системной службы. Большая часть этого руководства посвящена пользовательским службам, но в конце есть раздел о том, как перейти от пользовательской службы к системной, когда вы будете к этому готовы.
Создание службы пользователя
Чтобы создать службу systemd, вам необходимо создать соответствующий файл модуля, который представляет собой простой текстовый файл конфигурации в стиле ini. В этом уроке мы будем использовать простой автономный юнит-файл, дополнительные подходы см. в systemd.unit.
Юнит-файлы для пользовательских сервисов можно поместить в несколько мест. Некоторым из них требуется root-доступ, но в вашем домашнем каталоге есть несколько возможных мест. Насколько я могу судить, для них нет установленного варианта по умолчанию, поэтому в этом руководстве мы собираемся использовать ~/.config/systemd/user/ .
Поэтому сохраните следующее описание модуля как ~/.config/systemd/user/python_demo_service.service :
После того, как вы это сделаете, systemd найдет наш сервис:
Параметры модуля для служб systemd задокументированы в systemd.service.
Подключение службы к скрипту Python
Теперь мы можем приступить к написанию фактического кода Python для службы. Давайте начнем с малого со сценария, который просто печатает сообщение каждые 5 секунд. Сохраните следующий скрипт как python_demo_service.py в любом каталоге по вашему выбору:
Чтобы связать наш сервис с нашим скриптом, расширьте файл модуля следующим образом:
Запуск и остановка службы вручную
Теперь наш сервис можно запустить:
В зависимости от вашей версии systemd вам может потребоваться перезагрузить пользовательский демон, чтобы наш сервис можно было найти и запустить.
Обратите внимание, что эта команда немедленно возвращает значение. Это потому, что systemd создал отдельный процесс, который запускает наш скрипт. Это означает, что нам не нужно заботиться о неприятных деталях правильного разветвления процесса демона, поскольку systemd делает всю работу за нас. Ура!
Мы можем проверить, работает ли наш сервис:
В первой строке вывода мы видим описание из файла нашего модуля. Выходные данные также сообщают нам о состоянии нашего сервиса и PID, под которым он работает.
Очевидно, что наш сервис также можно остановить:
STDOUT и STDERR
Возможно, вы заметили, что вывод вызовов печати нашего скрипта не отображается на вашем терминале. Это связано с тем, что systemd отсоединила процесс службы от этого терминала, а также перенаправила потоки STDOUT и STDERR процесса.
Необходимо помнить, что в Python STDOUT и STDERR буферизуются. При работе в терминале это означает, что вывод будет отображаться только после того, как будет записана новая строка ( \n ). Однако STDOUT и STDERR нашего сервиса являются конвейерами, и в этом случае буфер очищается только после его заполнения. Следовательно, сообщения скрипта появляются в журналах systemd только после того, как он произвел еще больше вывода.
Чтобы избежать этого эффекта, нам нужно отключить буферизацию STDOUT и STDERR, и одна из возможностей сделать это — установить переменную среды PYTHONUNBUFFERED. Это можно сделать прямо в нашем юнит-файле, добавив в секцию [Service] следующую строку:
Как всегда, когда вы изменяете файл модуля, вам нужно указать systemd перезагрузить его конфигурацию и (если ваша служба в данный момент запущена) перезапустить службу:
Вывод нашего скрипта теперь должен отображаться в журналах systemd, которые по умолчанию перенаправляются в syslog:
Еще один способ отобразить выходные данные вашего сервиса — через
Существует множество других возможных конфигураций ведения журнала. Например, вместо этого вы можете перенаправить STDOUT и STDERR в файлы. Подробнее см. в systemd.exec.
Автоматический запуск службы во время загрузки
Многие службы предназначены для автоматического запуска при загрузке системы. Этого легко добиться с помощью systemd. Сначала нам нужно привязать наш сервис к подходящему target: target — это специальные юниты systemd, которые используются для группировки других юнитов и для синхронизации при запуске. См. systemd.target для получения подробной информации о целях в целом и systemd.special для списка встроенных целей.
Для пользовательских служб лучше всего подходит default.target. Добавьте в файл модуля следующее:
Теперь наша служба готова к автоматическому запуску, но для того, чтобы это действительно произошло, мы должны сначала включить службу:
Если вы перезагрузите систему сейчас, наша служба будет запущена автоматически после того, как вы войдете в систему. После закрытия вашего последнего сеанса экземпляр systemd вашего пользователя (а вместе с ним и наша служба) будет закрыт. Вы можете сделать экземпляр systemd вашего пользователя независимым от сеансов вашего пользователя (чтобы наш сервис запускался во время загрузки, даже если вы не входите в систему, а также продолжал работать до выключения/перезагрузки) через
Чтобы отключить автозапуск, просто отключите службу:
Обратите внимание, что простое включение службы не запускает ее, а только активирует автозапуск во время загрузки. Точно так же отключение службы не останавливает ее, а только отключает автозапуск во время загрузки. Если вы хотите немедленно запустить/остановить службу, вам все равно придется сделать это вручную, как описано выше, в дополнение к включению/отключению службы.
Чтобы проверить, включен ли ваш сервис, используйте
Автоматический перезапуск службы после сбоя
Как и в случае с любым другим программным обеспечением, ваш сервис может выйти из строя. В этом случае systemd может автоматически попытаться перезапустить его. По умолчанию systemd этого не делает, поэтому вам нужно включить эту функцию в файле модуля.
У systemd есть несколько опций для точной настройки того, при каких обстоятельствах ваш сервис должен быть перезапущен. Хорошей отправной точкой является установка Restart=on-failure в разделе [Service] файла модуля:
Это указывает systemd перезапустить ваш демон, когда он завершает работу с ненулевым кодом выхода. Другие настройки перезапуска и связанные с ними параметры задокументированы в файле systemd.оказание услуг. Как всегда, вам нужно запустить systemctl --user daemon-reload, чтобы эти изменения вступили в силу.
Мы можем имитировать сбой, уничтожив нашу службу с помощью сигнала SIGKILL:
После этого журналы покажут, что systemd перезапустила нашу службу:
Уведомление systemd о готовности службы
Часто служба должна выполнить некоторую инициализацию, прежде чем она будет готова выполнять свою фактическую работу. Ваша служба может уведомить systemd после завершения инициализации. Это особенно полезно, когда от вашего сервиса зависят другие сервисы, так как это позволяет systemd откладывать их запуск до тех пор, пока ваш сервис не будет действительно готов.
Уведомление выполняется с помощью системного вызова sd_notify. Мы будем использовать пакет python-systemd для его запуска, поэтому убедитесь, что он установлен. Затем добавьте в наш скрипт следующие строки:
Вам также потребуется изменить тип вашей службы с простого (по умолчанию, который мы использовали ранее) на уведомление . Добавьте следующую строку в раздел [Service] вашего юнит-файла и после этого вызовите systemctl --user daemon-reload.
Затем вы можете увидеть уведомление в действии, (повторно)запустив службу: systemctl будет ждать уведомления службы перед возвратом.
С помощью sd_notify можно сделать гораздо больше, подробности см. в документации.
Создание системной службы
Получив работающую пользовательскую службу, вы можете превратить ее в системную службу. Помните, однако, что системные службы работают в центральном экземпляре systemd системы и имеют больший потенциал для нарушения стабильности или безопасности вашей системы, если они не реализованы правильно. Во многих случаях этот шаг на самом деле не нужен, и пользовательский сервис вполне подойдет.
Остановка и отключение пользовательской службы
Прежде чем превратить нашу службу в системную, убедитесь, что она остановлена и отключена. В противном случае мы можем получить как пользовательскую, так и системную службу.
Перемещение файла модуля
Ранее мы сохраняли файл нашего модуля в каталоге, подходящем для пользовательских служб ( ~/.config/systemd/user/ ). Как и в случае с файлами юнитов, systemd ищет файлы системных юнитов более чем в одном каталоге. Мы будем использовать /etc/systemd/system/ ', поэтому переместите файл вашего модуля туда и убедитесь, что у него есть правильные разрешения
Наш сервис теперь системный! Это также означает, что вместо использования systemctl --user . теперь мы будем использовать systemctl. (без параметра --user) вместо этого (или sudo systemctl . если мы что-то изменяем). Например:
Аналогичным образом используйте journalctl --unit python_demo_service для отображения журналов системной службы.
Перемещение скрипта Python
До сих пор вы, вероятно, хранили скрипт Python службы где-то в своем домашнем каталоге. Это нормально для пользовательской службы, но не оптимально для системной службы. Отдельный подкаталог в /usr/local/lib — лучший выбор:
Очевидно, что нам также нужно изменить расположение скрипта в файле нашего модуля: обновить ExecStart=. линия до
и перезагрузите изменения с помощью sudo systemctl daemon-reload .
Использование специального пользователя службы
Системные службы по умолчанию запускаются от имени пользователя root , что представляет угрозу безопасности. Вместо этого мы будем использовать учетную запись пользователя, выделенную для службы, чтобы мы могли использовать обычные механизмы безопасности (например, права доступа к файлам) для точного определения того, к чему наша служба может получить доступ, а к чему нет.
Хорошим выбором имени пользователя службы является имя службы. Для создания пользователя воспользуемся командой useradd:
После того как вы создали пользователя, добавьте следующую строку в раздел [Service] вашего файла модуля:
После перезагрузки конфигурации systemd, перезапустив нашу службу, мы можем убедиться, что она работает от имени правильного пользователя:
Что делать дальше
Теперь у нас есть базовая реализация системного сервиса systemd на Python. В зависимости от вашей цели, есть много способов двигаться вперед. Вот несколько идей:
- Добавить поддержку перезагрузки конфигурации службы без аппаратного перезапуска. См. параметр ExecReload.
- Изучите другие функции пакета python-systemd, например модуль systemd.journal для расширенного взаимодействия с журналом systemd.
И, конечно же, если вы обнаружите ошибку в этом руководстве или у вас есть дополнение, не стесняйтесь создавать проблему или запрос на вытягивание.
Вот краткое руководство по запуску скрипта Python при запуске Linux
В этой статье мы объясним, как легко выполнить скрипт Python при запуске Linux. На самом деле вставка сценария в сервис очень полезна, если мы хотим создать устройство (например, RTU), которое начинает собирать данные при запуске операционной системы. Кроме того, сервис крайне удобно запускать или останавливать с помощью одной командной строки.
Скрипт, Start.sh и Stop.sh
Предположим, что наш скрипт Python, который нужно выполнить, находится в папке:
/home/pi/Script/MyScript.py
К этому файлу мы должны добавить еще два файла: Start.sh и Stop.sh. Файл Start.sh будет служить для запуска сценария, а файл Stop.sh — для его остановки. Давайте начнем создавать файлы, открыв терминал и набрав:
нажмите Start.sh
sudo pico Start.shвставляем содержимое:
для сохранения нажмите CTRL + O, нажмите Enter, а затем закройте с помощью CTRL + X. Мы устанавливаем права доступа к файлу следующим образом:
chmod a+x Start.sh
Теперь давайте создадим файл Stop.sh следующим образом:
$ touch Stop.sh
$ sudo pico Stop.shвставляем содержимое:
сохраните, нажав CTRL + O, нажмите Enter, а затем закройте, нажав CTRL + X. Мы устанавливаем права доступа к файлу следующим образом:
chmod a+x Stop.sh
Как видите, код принудительно останавливает скрипт, мгновенно прерывая его выполнение.
Скрипт как услуга
Теперь давайте создадим службу, которая запускает скрипт при старте операционной системы. Всегда из терминала запускаем следующую команду:
sudo pico /etc/systemd/system/name_script.service
и вставьте следующее содержимое:
[Unit]
Description=NAME_SCRIPT service
After=network.target[Сервис]
Type=simple
ExecStart=/bin/bash /home/pi/Script/Start.sh
ExecStop=/bin/bash /home/pi/Script/Stop.sh
Перезапускать=всегда
< em>RestartSec=5
TimeoutSec=60
RuntimeMaxSec=infinity
PIDFile=/tmp/nome_script .pid[Установить]
WantedBy=multi-user.targetне забудьте изменить name_script на имя, связанное с вашим скриптом. Сохраните, нажав CTRL + O, затем нажмите Enter и закройте, нажав CTRL + X. На этом этапе мы запускаем последние команды:
sudo systemctl enable /etc/systemd/system/name_script.service
sudo systemctl daemon-reload
запуск sudo service name_scriptНа этом этапе ваш скрипт будет введен в эксплуатацию и запущен. Чтобы проверить наличие ошибок или нет, вы можете запустить эту команду:
Пример программы
Вы можете использовать любую программу, которую хотите запускать при загрузке; для этого урока мы используем пример программы Python, которая будет говорить при запуске Raspberry Pi. Этот пример программы будет использовать пакет Espeak, чтобы заставить Raspberry Pi произнести фразу «Добро пожаловать в мир роботов».
Если у вас не установлен пакет Espeak, запустите в терминале следующую команду для установки:
В каталоге /home/pi откройте файл для редактирования:
И введите следующий код и сохраните его (нажмите CTRL+X и введите Y ).
Способ 1: rc.local
Первый способ запустить программу на Raspberry Pi при запуске — использовать файл rc.local. Чтобы запустить команду или программу при загрузке Pi, вы можете добавить команды в файл rc.local. Это особенно полезно, если вы хотите включить Pi в безголовом режиме (то есть без подключенного монитора) и запустить программу без настройки или ручного запуска.
Редактирование rc.local
На своем Pi отредактируйте файл /etc/rc.local с помощью редактора по вашему выбору. Вы должны редактировать его с правами суперпользователя:
Добавьте команды для выполнения программы Python, предпочтительно используя абсолютную ссылку на местоположение файла (предпочтительнее полный путь к файлу). Обязательно оставьте строку exit 0 в конце, затем сохраните файл и выйдите. В nano для выхода нажмите Ctrl-x, а затем Y.
Если ваша программа работает непрерывно (выполняет бесконечный цикл) или, скорее всего, не завершится, вы должны обязательно разветвить процесс, добавив амперсанд ("&") в конец команды, например:
Pi запустит эту программу при загрузке и до запуска других служб. Если вы не укажете амперсанд и ваша программа будет работать непрерывно, Pi не завершит процесс загрузки. Амперсанд позволяет запустить команду в отдельном процессе и продолжить загрузку с работающим основным процессом.
Теперь перезагрузите Pi, чтобы проверить его:
Советы
Кроме того, обязательно указывайте абсолютные имена файлов, а не относительные к вашей домашней папке. Например, используйте `/home/pi/myscript.py` вместо `myscript.py`.
Если вы добавите сценарий в /etc/rc.local, он будет добавлен в последовательность загрузки. Если ваш код зависает, последовательность загрузки не может быть продолжена. Поэтому будьте осторожны с тем, какой код вы пытаетесь запустить при загрузке, и проверьте код пару раз. Вы также можете записать выходные данные скрипта и ошибки в текстовый файл (скажем, log.txt) и использовать его для отладки.
Способ 2: .bashrc
Второй способ запустить программу на Raspberry Pi при запуске — изменить файл .bashrc. С помощью метода .bashrc ваша программа python будет запускаться при входе в систему (что происходит автоматически, когда вы загружаетесь и переходите непосредственно на рабочий стол), а также каждый раз, когда открывается новый терминал или когда устанавливается новое соединение SSH. Поместите свою команду в конец «/home/pi/.bashrc». Программу можно прервать с помощью «ctrl-c» во время ее работы!
Перейдите к последней строке скрипта и добавьте:
Приведенный выше оператор echo используется для демонстрации того, что команды в файле .bashrc выполняются при загрузке, а также при подключении к консоли bash.
Теперь перезагрузите Pi, чтобы услышать, как Pi говорит при запуске.
На изображении ниже показано, что команды, добавленные в файл .bashrc, выполняются даже при открытии нового терминала.
Способ 3: каталог init.d
Третий способ запустить программу на Raspberry Pi при запуске — добавить программу (которая будет запускаться при загрузке) в каталог /etc/init.d. Этот каталог содержит сценарии, которые запускаются в процессе загрузки (кроме того, все программы здесь выполняются при завершении работы или перезагрузке системы).
Добавьте программу, которая будет запускаться при запуске, в каталог init.d, используя следующие строки:
Перейдите в каталог инициализации и откройте пример скрипта
Добавьте следующие строки в образец сценария, чтобы сделать его сценарием инициализации Linux Standard Base (LSB) (стандарт структуры программной системы, включая иерархию файловой системы, используемую в операционной системе Linux).
Сценарии init.d требуют документирования вышеуказанных зависимостей времени выполнения, чтобы можно было проверить текущий порядок загрузки, порядок загрузки с использованием этих зависимостей и параллельный запуск сценариев загрузки для ускорения процесса загрузки. р>
Вы можете научиться писать скрипты init.d, следуя этому руководству здесь.
Сделайте пример сценария в каталоге инициализации исполняемым, изменив его разрешение.
Выполните эту команду:
Теперь перезагрузитесь, чтобы услышать, как Pi говорит при запуске.
Метод 4: SYSTEMD
Четвертый способ запустить программу на Raspberry Pi при запуске — использовать файлы systemd. systemd предоставляет стандартный процесс управления тем, какие программы запускаются при загрузке системы Linux. Обратите внимание, что systemd доступен только в версиях Raspbian OS для Jessie.
Шаг 1. Создайте файл модуля
Откройте образец файла модуля с помощью команды, как показано ниже:
Добавить следующий текст:
Вы должны сохранить и выйти из редактора nano.
Это определяет новую службу под названием «Образец службы», и мы просим запустить ее, как только станет доступна многопользовательская среда. Параметр «ExecStart» используется для указания команды, которую мы хотим запустить. «Тип» установлен на «ожидание», чтобы гарантировать, что команда ExecStart запускается только тогда, когда все остальное загружено. Обратите внимание, что пути являются абсолютными и определяют полное расположение Python, а также расположение нашего скрипта Python.
Чтобы сохранить текстовый вывод скрипта в файле журнала, вы можете изменить строку ExecStart на:
Права доступа к файлу модуля должны быть установлены на 644 :
Шаг 2. Настройка systemd
Теперь, когда юнит-файл определен, мы можем указать systemd запустить его во время последовательности загрузки:
Перезагрузите Pi, и ваш пользовательский сервис должен запуститься:
Способ 5: crontab
Подробное руководство по использованию crontab для запуска программы при загрузке можно найти здесь.
Вы можете использовать любой из этих методов для запуска вашей программы при загрузке, если точка, в которой ваш скрипт Python запускается в последовательности запуска, не является жизненно важной. Если ваш сценарий зависит от каких-либо системных функций, доступных в этот момент времени, таких как подключение и доступность сети, каталог /home/pi смонтирован и готов к использованию или системное время было обновлено NTP, тогда он будет идеально подходит для использования методов systemd или init.d. Эти методы управляют моментом загрузки, в котором ваш скрипт выполняется во время загрузки.
Ваше желание — моя команда.
Подробнее
Хотите создать несколько потрясающих проектов с помощью Raspberry Pi и роботов? Собери свой собственный робот-автомобиль GoPiGo! Посетите нашу страницу проектов, чтобы увидеть больше примеров забавных проектов робототехники с вашим Raspberry Pi!
Вопросы
Есть вопрос? Нужна помощь? Спросите на нашем форуме!
Подробнее!
Если вам понравился этот урок, рассмотрите возможность приобретения Raspberry Pi здесь и SD-карты с Raspbian для роботов здесь, чтобы попробовать себя.
Читайте также: