Лучшие практики упаковки Python Daemon
У меня есть инструмент, который я написал на Python и обычно должен запускаться как демон. Каковы наилучшие методы упаковки этого инструмента для распространения, в частности, как следует обрабатывать файлы настроек и исполняемый файл / скрипт демона?
Соответственно, существуют ли какие-либо общие инструменты для настройки демона для запуска при загрузке в соответствии с данной платформой (например, сценарии инициализации в Linux, службы в Windows, запуск в OS X)?
Ответов (10)10
Чтобы ответить на одну часть вашего вопроса, я не знаю никаких инструментов, которые могли бы переносить установку демона даже в системах Linux, не говоря уже о Windows или Mac OS X.
Кажется, что большинство дистрибутивов Linux сейчас используются start-stop-daemon
в сценариях инициализации, но вы все равно будете иметь небольшие различия в макете файловой системы и большие различия в упаковке. Использование autotools / configure или distutils / easy_install, если ваш проект полностью основан на Python, значительно упростит сборку пакетов для различных дистрибутивов Linux / BSD.
Windows - это совершенно другая игра, и для нее потребуются расширения Win32 Марка Хаммонда и, возможно , расширения WMI Тима Голдена .
Я не знаю Launchd, за исключением того, что «ничего из вышеперечисленного» не имеет значения.
Чтобы получить советы по демонизации скриптов Python, я бы обратился к приложениям Python, которые действительно делают это в реальном мире, например, внутри Twisted.
Не серебряная пуля за то, о чем вы просите, но проверьте супервайзера . Он обрабатывает все забавные моменты управления процессами. Я активно использую его в большой производственной среде. Кроме того, он написан на Python!
Эта запись в блоге прояснила для меня, что на самом деле есть два распространенных способа запустить вашу программу Python в качестве демона (я не понял этого так ясно из существующих ответов):
Есть два подхода к написанию приложений-демонов, таких как серверы, на Python.
- Первый - выполнять все задачи по запуску и остановке демонов в самом коде Python . Самый простой способ сделать это - использовать
python-daemon
пакет, который в конечном итоге может попасть в дистрибутив Python.
Ответ Poeljapon является примером этого 1-го подхода, хотя он не использует python-daemon
пакет, а ссылается на собственный, но очень чистый скрипт python.
- Другой подход - использовать инструменты, предоставляемые операционной системой . В случае Debain это означает написание сценария инициализации, использующего
start-stop-daemon
программу.
Ответ Али Афшара - это пример сценария оболочки второго подхода с использованием start-stop-daemon
.
В записи блога, которую я цитировал, есть пример сценария оболочки и некоторые дополнительные сведения о таких вещах, как запуск вашего демона при запуске системы и автоматический перезапуск вашего демона, когда он остановился по какой-либо причине.
"вообще должен запускаться как демон?"
Не имеет - на первый взгляд - большого смысла. «Вообще» не имеет смысла. Либо демон, либо нет. Возможно, вы захотите обновить свой вопрос.
Примеры демонов можно найти в таких демонах, как httpd Apache, или о любом сервере базы данных (они же демоны), или о почтовом демоне SMTPD.
Или, возможно, почитайте что-нибудь попроще, например, демон FTP, демон SSH, демон Telnet.
В мире Linux у вас будет каталог установки вашего приложения, некоторый рабочий каталог, а также каталоги файлов конфигурации.
Мы используем /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 .
Лучший инструмент, который я нашел для помощи со сценариями 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, который я всегда рекомендую.
В системах Linux системный менеджер пакетов (Portage для Gentoo, Aptitude для Ubuntu / Debian, yum для Fedora и т. Д.) Обычно заботится об установке программы, включая размещение сценариев инициализации в нужных местах. Если вы хотите распространять свою программу для Linux, вы можете подумать о том, чтобы связать ее в надлежащем формате для менеджеров пакетов различных дистрибутивов.
Этот совет, очевидно, не имеет отношения к системам, в которых нет менеджеров пакетов (я думаю, Windows и Mac).
В Интернете есть множество фрагментов, предлагающих написать демона на чистом питоне (без сценариев bash)
http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ выглядит чистым ...
Если вы хотите написать свой собственный,
принцип тот же, что и с функцией демона bash.
По сути:
В начале:
- вы переходите к другому процессу
- откройте файл журнала, чтобы перенаправить ваш stdout и stderr
- Сохраните pid где-нибудь.
На остановке:
- Вы отправляете SIGTERM процессу с pid, хранящимся в вашем pidfile.
- С помощью signal.signal (signal.SIGTERM, sigtermhandler) вы можете привязать процедуру остановки к сигналу SIGTERM.
Однако я не знаю ни одного широко используемого пакета, делающего это.
Я не помню, где я его скачал ... но это лучший демонизирующий скрипт, который я нашел. Он прекрасно работает (на 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 и т. Д.
Проверьте модуль демона Бена Финни. Он начал писать PEP, ориентированный на python 3.X:
http://www.python.org/dev/peps/pep-3143/
Но реализация уже доступна здесь: