【问题标题】:Python Daemon Packaging Best PracticesPython 守护进程打包最佳实践
【发布时间】:2010-10-09 23:30:28
【问题描述】:

我有一个用 python 编写的工具,通常应该作为守护进程运行。打包此工具以进行分发的最佳实践是什么,特别是应如何处理设置文件和守护程序可执行文件/脚本?

相关的是,是否有任何通用工具可以根据给定平台设置守护程序以在启动时运行(即 Linux 上的 init 脚本、Windows 上的服务、launchd在 os x) 上?

【问题讨论】:

标签: python packaging setuptools distutils


【解决方案1】:

我发现帮助 init.d 脚本的最佳工具是“start-stop-daemon”。它将运行任何应用程序、监控运行/pid 文件、在必要时创建它们、提供停止守护进程的方法、设置进程用户/组 ID,甚至可以后台处理您的进程。

例如,这是一个可以启动/停止 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 一起使用的示例,我总是会推荐它。

【讨论】:

    【解决方案2】:

    要回答您的部分问题,我所知道的任何工具都无法在 Linux 系统上进行守护程序设置,更不用说 Windows 或 Mac OS X。

    现在大多数 Linux 发行版似乎都在 init 脚本中使用 start-stop-daemon,但在文件系统布局和打包方面仍然会有很大差异。使用 autotools/configure 或 distutils/easy_install(如果您的项目全是 Python)将大大有助于更轻松地为不同的 Linux/BSD 发行版构建包。

    Windows 是一个完全不同的游戏,需要Mark Hammond's win32 扩展,可能还需要Tim Golden's WMI 扩展。

    我不知道 Launchd,除了“以上都不相关”。

    有关守护 Python 脚本的技巧,我会寻找在现实世界中实际执行此操作的 Python 应用程序,例如在 Twisted 中。

    【讨论】:

      【解决方案3】:

      互联网上有很多 sn-ps 提供用纯 Python 编写守护程序(无 bash 脚本)

      http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/ 看起来很干净...

      如果你想自己写,
      原理与bash daemon函数相同。

      基本上:

      开始时:

      • 你 fork 到另一个进程
      • 打开一个日志文件来重定向你的 标准输出和标准错误
      • 将 pid 保存在某处。

      停止:

      • 您将 SIGTERM 发送到进程,其中 pid 存储在您的 pidfile 中。
      • 使用 signal.signal(signal.SIGTERM, sigtermhandler) 你可以绑定一个停止 SIGTERM 信号的过程。

      不过,我不知道有任何广泛使用的软件包可以做到这一点。

      【讨论】:

      • +1 用于 Python 守护程序。我实际上使用了与此类似的配方,除了我使用 Bash 脚本中的 start-stop-daemon 启动它。也许一步太多了,但它给了我一种温暖的模糊感觉,就像所有其他守护进程一样!
      【解决方案4】:

      检查 Ben Finney 的守护进程模块。他已经开始编写针对 python 3.X 的 PEP:

      http://www.python.org/dev/peps/pep-3143/

      但是这里已经有一个实现了:

      http://pypi.python.org/pypi/python-daemon/

      【讨论】:

        【解决方案5】:

        对于您的要求,这不是灵丹妙药,但请查看 supervisord。它处理管理流​​程的所有有趣部分。我在大型生产环境中大量使用它。而且,它是用 Python 编写的!

        【讨论】:

          【解决方案6】:

          我不记得我在哪里下载了它……但这是我找到的最好的守护进程脚本。它运行良好(在 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等的位置...

          【讨论】:

          【解决方案7】:

          在 Linux 系统上,系统的包管理器(Gentoo 的 Portage、Ubuntu/Debian 的 Aptitude、Fedora 的 yum 等)通常负责安装程序,包括将 init 脚本放置在正确的位置。如果您想为 Linux 分发您的程序,您可能需要考虑将其捆绑成适合各种发行版包管理器的格式。

          这个建议显然与没有包管理器的系统无关(我认为是 Windows 和 Mac)。

          【讨论】:

          • 还有许多其他 Unices 的包装系统!例如用于 NetBSD 的 pkgsrc。
          • 有趣,我不知道
          【解决方案8】:

          blog entry 让我清楚地知道,实际上有两种常见的方法可以让你的 Python 程序作为守护进程运行(我没有从现有答案中这么清楚地弄清楚这一点):

          有两种方法可以编写像服务器这样的守护程序应用程序 在 Python 中。

          • 首先是处理所有的sarting和 在 Python 代码本身中停止守护进程。最简单的方法是 使用python-daemon 包,它最终可能会成功 进入 Python 发行版。

          Poeljapon's answer 是第一种方法的示例,虽然它不使用 python-daemon 包,但链接到自定义但非常干净的 python 脚本。

          • 另一种方法是使用工具 由操作系统提供。对于 Debain,这意味着 编写一个使用 start-stop-daemon 的初始化脚本 程序。

          Ali Afshar's answer 是第二种方法的 shell 脚本示例,使用 start-stop-daemon。

          我引用的博客条目有一个 shell 脚本示例,以及一些额外的细节,例如在系统启动时启动你的守护进程,以及在它因任何原因停止时自动重新启动你的守护进程。

          【讨论】:

            【解决方案9】:

            如果错了,请纠正我,但我相信问题是如何部署守护程序。将您的应用设置为通过 pip 安装,然后将 entry_point 设置为 cli(daemon())。然后创建一个简单地运行$app_name &

            的初始化脚本

            【讨论】:

              【解决方案10】:

              “一般应该作为守护进程运行?”

              从表面上看,没有什么意义。 “一般”是不明智的。它要么是守护进程,要么不是。您可能想更新您的问题。

              有关守护程序的示例,请阅读诸如 Apache 的 httpd 或任何数据库服务器(它们是守护程序)或 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。

              【讨论】:

              • 你好强悍!?守护进程只是被守护的程序。有时将它们作为 Ctrl-c 的常规进程运行很有用,在标准输出等上查看输出。
              • @Paul:同意。你能澄清一下这个问题吗?
              猜你喜欢
              • 2020-08-10
              • 2018-03-10
              • 2010-09-24
              • 2011-12-16
              • 1970-01-01
              • 2010-11-18
              • 2011-10-31
              • 1970-01-01
              • 2014-06-04
              相关资源
              最近更新 更多