Лучшие практики упаковки демонов Python
-
09-09-2019 - |
Вопрос
У меня есть инструмент, который я написал на python и обычно должен запускаться как демон.Каковы наилучшие методы упаковки этого инструмента для распространения, в частности, как следует обращаться с файлами настроек и исполняемым файлом / скриптом daemon?
В связи с этим существуют ли какие-либо общие инструменты для настройки демона для запуска при загрузке в соответствии с данной платформой (т.е. инициализация скрипты в Linux, сервисы в Windows, запуск в os x)?
Решение
Чтобы ответить на одну часть вашего вопроса, я не знаю инструментов, которые переносили бы daemon setup даже в системах Linux, не говоря уже о Windows или Mac OS X.
Большинство дистрибутивов Linux, похоже, используют start-stop-daemon
теперь внутри скриптов инициализации, но у вас по-прежнему будут незначительные различия в компоновке файловой системы и большие различия в упаковке.Использование autotools / configure или distutils / easy_install, если ваш проект полностью основан на Python, значительно упростит сборку пакетов для различных дистрибутивов Linux / BSD.
Windows - это совершенно другая игра, которая потребует win32 Марка Хэммонда расширения и, возможно, WMI Тима Голдена Расширения.
Я не знаю, что такое Launchd, за исключением того, что "ничего из вышеперечисленного" не имеет отношения к делу.
За советами по демонизации скриптов на Python я бы обратился к приложениям на Python, которые на самом деле делают это в реальном мире, например, внутри Twisted.
Другие советы
Лучший инструмент, который я нашел для помощи со скриптами init.d, - это "start-stop-daemon".Он будет запускать любое приложение, отслеживать файлы run / pid, создавать их при необходимости, предоставлять способы остановки демона, устанавливать идентификаторы пользователей / групп процесса и даже может работать в фоновом режиме для вашего процесса.
Например, это скрипт, который может запускать / останавливать сервер wsgi:
#! /bin/bash
case "$1" in
start)
echo "Starting server"
# Activate the virtual environment
. /home/ali/wer-gcms/g-env/bin/activate
# Run start-stop-daemon, the $DAEMON variable contains the path to the
# application to run
start-stop-daemon --start --pidfile $WSGI_PIDFILE \
--user www-data --group www-data \
--chuid www-data \
--exec "$DAEMON"
;;
stop)
echo "Stopping WSGI Application"
# Start-stop daemon can also stop the application by sending sig 15
# (configurable) to the process id contained in the run/pid file
start-stop-daemon --stop --pidfile $WSGI_PIDFILE --verbose
;;
*)
# Refuse to do other stuff
echo "Usage: /etc/init.d/wsgi-application.sh {start|stop}"
exit 1
;;
esac
exit 0
Вы также можете увидеть там пример того, как использовать его с virtualenv, который я бы всегда рекомендовал.
В Интернете есть много фрагментов, предлагающих написать демон на чистом python (без bash-скриптов).
http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ выглядит чистым...
Если вы хотите написать свой собственный,
принцип тот же, что и в случае с функцией демона bash.
В основном:
При запуске:
- вы переходите к другому процессу
- откройте файл журнала, чтобы перенаправить ваши стандартные параметры stdout и stderr
- Сохраните где-нибудь pid.
Вкл. стоп:
- Вы отправляете SIGTERM процессу с pid, сохраненным в вашем pid-файле.
- С помощью signal.signal(signal.SIGTERM, sigtermhandler) вы можете привязать процедуру остановки к сигналу SIGTERM.
Однако я не знаю ни одного широко используемого пакета, делающего это.
Проверьте модуль демона Бена Финни.Он начал писать PEP, ориентированный на python 3.X:
http://www.python.org/dev/peps/pep-3143/
Но реализация уже доступна здесь :
Это не серебряная пуля для того, о чем вы просите, но проверьте руководитель.Он обрабатывает все интересные моменты управления процессами.Я активно использую его в большой производственной среде.Кроме того, он написан на Python!
Я не могу вспомнить, где я его скачал...но это лучший демонизирующий скрипт, который я нашел.Он прекрасно работает (на Mac и Linux). (сохраните его как daemonize.py)
import sys, os
def daemonize (stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
# Perform first fork.
try:
pid = os.fork( )
if pid > 0:
sys.exit(0) # Exit first parent.
except OSError, e:
sys.stderr.write("fork #1 failed: (%d) %sn" % (e.errno, e.strerror))
sys.exit(1)
# Decouple from parent environment.
os.chdir("/")
os.umask(0)
os.setsid( )
# Perform second fork.
try:
pid = os.fork( )
if pid > 0:
sys.exit(0) # Exit second parent.
except OSError, e:
sys.stderr.write("fork #2 failed: (%d) %sn" % (e.errno, e.strerror))
sys.exit(1)
# The process is now daemonized, redirect standard file descriptors.
for f in sys.stdout, sys.stderr: f.flush( )
si = file(stdin, 'r')
so = file(stdout, 'a+')
se = file(stderr, 'a+', 0)
os.dup2(si.fileno( ), sys.stdin.fileno( ))
os.dup2(so.fileno( ), sys.stdout.fileno( ))
os.dup2(se.fileno( ), sys.stderr.fileno( ))
В вашем сценарии вы бы просто:
from daemonize import daemonize
daemonize()
И вы также можете указать места для перенаправления stdio, err и т.д...
В системах Linux системный менеджер пакетов (Portage для Gentoo, Aptitude для Ubuntu / Debian, yum для Fedora и т.д.) Обычно заботится об установке программы, включая размещение сценариев инициализации в нужных местах.Если вы хотите распространять свою программу для Linux, возможно, вам захочется объединить ее в надлежащий формат для менеджеров пакетов различных дистрибутивов.
Этот совет, очевидно, неуместен в системах, в которых нет менеджеров пакетов (я думаю, Windows и Mac).
Это запись в блоге мне стало ясно, что на самом деле есть два распространенных способа запустить вашу программу на Python как демон (я не понял этого так четко из существующих ответов):
Существует два подхода к написанию приложений-демонов, таких как серверы на Python.
- Первый заключается в том, чтобы выполняет все задачи по запуску и остановке демонов в самом коде Python.Самый простой способ сделать это - с помощью
python-daemon
пакет, который в конечном итоге может попасть в дистрибутив Python.
Ответ Поэльяпона является примером этого первого подхода, хотя он не использует python-daemon
пакет, но ссылки на пользовательский, но очень чистый скрипт на Python.
- Другой подход заключается в том, чтобы используйте инструменты , поставляемые операционной системой.В случае Debain это означает написание сценария инициализации, который использует
start-stop-daemon
программа.
Ответ Али Афшара является примером сценария оболочки 2-го подхода, использующего start-stop-daemon
.
В записи блога, которую я процитировал, есть пример сценария командной строки и некоторые дополнительные сведения о таких вещах, как запуск вашего демона при запуске системы и автоматический перезапуск вашего демона, когда он останавливался по какой-либо причине.
поправьте меня, если ошибаюсь, но я полагаю, что вопрос в том, как РАЗВЕРНУТЬ демон.Установите ваше приложение для установки через pip, а затем сделайте entry_point точкой входа cli(daemon())
.Затем создайте скрипт инициализации, который просто запускается $app_name &
"обычно должен запускаться как демон?"
В этом - на первый взгляд - нет большого смысла."Вообще" - это неразумно.Это либо демон, либо нет.Возможно, вы захотите обновить свой вопрос.
Для получения примеров демонов ознакомьтесь с такими демонами, как httpd от Apache или любой сервер базы данных (они являются демонами) или почтовый демон SMTPD.
Или, возможно, почитайте о чем-нибудь попроще, например о демоне FTP, SSH-демоне, Telnet-демоне.
В Linux world у вас будет каталог установки вашего приложения, некоторый рабочий каталог, а также каталоги файлов конфигурации.
Мы используем /opt/ourapp
для приложения (это Python, но мы не устанавливаем на Python lib/site-packages
)
Мы используем /var/ourapp
для рабочих файлов и наших конфигурационных файлов.
Мы могли бы использовать /etc/ourapp
для файлов конфигурации - это было бы согласованно, но мы этого не делаем.
Мы - пока - не используем init.d
скрипты для запуска.Но это последняя часть - автоматический запуск.На данный момент у нас есть системные администраторы, которые запускают демонов.
Частично это основано на http://www.pathname.com/fhs/ и http://tldp.org/LDP/Linux-Filesystem-Hierarchy/html/Linux-Filesystem-Hierarchy.html.