82

デーモンとして機能する単純なPythonスクリプトがあります。起動時にこのスクリプトを開始できるようにsystemdスクリプトを作成しようとしています。

現在のsystemdスクリプト:

[Unit]
Description=Text
After=syslog.target

[Service]
Type=forking
User=node
Group=node
WorkingDirectory=/home/node/Node/
PIDFile=/var/run/zebra.pid
ExecStart=/home/node/Node/node.py

[Install]
WantedBy=multi-user.target

node.py:

if __name__ == '__main__':
    with daemon.DaemonContext():
        check = Node()
        check.run()

runwhile Trueループが含まれています。

このサービスをで実行しようとしていますsystemctl start zebra-node.service。残念ながら、サービスはシーケンスの記述を終了しませんでした-Ctrl+Cを押す必要があります。スクリプトは実行されていますが、ステータスはアクティブ化されており、しばらくすると非アクティブ化に変わります。現在、私はpython-daemonを使用しています(ただし、それなしで試す前は、症状は似ていました)。

スクリプトにいくつかの追加機能を実装する必要がありますか、それともsystemdファイルが正しくありませんか?

4

5 に答える 5

123

起動シーケンスが完了しない理由は、 Typeの場合forking、起動プロセスが fork して終了することが予想されるためです ($ man systemd.service - search for forking を参照)。

メインプロセスのみを使用し、デーモン化しないでください

1 つのオプションは、少なくすることです。systemd では、デーモンを作成する必要がないことが多く、デーモン化せずにコードを直接実行できます。

#!/usr/bin/python -u
from somewhere import Node
check = Node()
check.run()

これにより、と呼ばれるより単純なタイプのサービスを使用できるsimpleようになるため、ユニット ファイルは次のようになります。

[Unit]
Description=Simplified simple zebra service
After=syslog.target

[Service]
Type=simple
User=node
Group=node
WorkingDirectory=/home/node/Node/
ExecStart=/home/node/Node/node.py
StandardOutput=syslog
StandardError=syslog

[Install]
WantedBy=multi-user.target

in python shebang は必要ありませ-uんが、stdout または stderr に何かを出力する-u場合は、出力バッファリングが行われず、出力された行がすぐに systemd によってキャッチされ、ジャーナルに記録されることに注意してください。それがなければ、少し遅れて表示されます。

この目的のために、ユニットファイルに行StandardOutput=syslogStandardError=syslog. ジャーナルの印刷出力を気にしない場合は、これらの行を気にしないでください (存在する必要はありません)。

systemdデーモン化を時代遅れにする

あなたの質問のタイトルはデーモン化について明示的に尋ねていますが、質問の核心は「サービスを実行する方法」であり、メインプロセスを使用する方がはるかに簡単に思えますが(デーモンをまったく気にする必要はありません)、それはあなたの質問への答えと見なすことができます。

「みんながやっている」という理由だけで、多くの人がデーモン化を使用していると思います。systemd では、デーモン化の理由は時代遅れになっていることがよくあります。デーモン化を使用するいくつかの理由があるかもしれませんが、現在はまれなケースです。

python -p編集:適切に修正されましたpython -u。ありがとう

于 2015-05-12T11:29:02.770 に答える
15

PID ファイルを作成していません。

systemd は、プログラムがその PID を に書き込むことを期待しています/var/run/zebra.pid。そうしないと、systemdはおそらくプログラムが失敗していると判断し、プログラムを非アクティブ化します。

PID ファイルを追加するには、lockfileをインストールし、コードを次のように変更します。

import daemon
import daemon.pidlockfile 

pidfile = daemon.pidlockfile.PIDLockFile("/var/run/zebra.pid")
with daemon.DaemonContext(pidfile=pidfile):
    check = Node()
    check.run()

(簡単なメモ: の最近の更新でlockfileAPI が変更され、python-daemon と互換性がなくなりました。修正するには、 を編集し、インポートからdaemon/pidlockfile.py削除して、 を追加します。)LinkFileLockfrom lockfile.linklockfile import LinkLockFile as LinkFileLock

もう1つ注意しDaemonContextてください。プログラムの作業ディレクトリをに変更し/WorkingDirectoryサービスファイルを役に立たなくします。DaemonContext別のディレクトリに chdir する場合は、 DaemonContext(pidfile=pidfile, working_directory="/path/to/dir").

于 2012-10-26T07:25:18.240 に答える
4

また、ほとんどdaemon_context=Trueの場合、 を作成するときに設定する必要がありますDaemonContext()

これはpython-daemon、init システムで実行されている場合に親プロセスから切り離されないことが検出されるためです。で実行されているデーモン プロセスがそうsystemdすることが期待されます。Type=forkingしたがって、それが必要です。そうしないと、systemd待機し続け、最終的にプロセスを強制終了します。

興味がある場合は、python-daemonのデーモン モジュールに次のコードが表示されます。

def is_detach_process_context_required():
    """ Determine whether detaching process context is required.

        Return ``True`` if the process environment indicates the
        process is already detached:

        * Process was started by `init`; or

        * Process was started by `inetd`.

        """
    result = True
    if is_process_started_by_init() or is_process_started_by_superserver():
        result = False

うまくいけば、これはよりよく説明します。

于 2013-07-25T02:57:30.447 に答える