pythonをデーモン化するメモ

  • 10
    Like
  • 3
    Comment

pythonで書いたものをデーモンにしたい

さくらのVPSにてpythonで書いたプログラムを常に走らせたかった。
おまけにsystemctlで操作できるので楽ちん。
やり方は以下のパクリ。
Systemdを使ってさくっと自作コマンドをサービス化してみる

環境

  • さくらのVPS
  • CentOS 7

How to

プログラム

/opt/python_daemon.py
#!/usr/bin/env python
import time
import os
import sys

def main_unit():#10秒おきに時刻を書き込む
    while True:
        filepath = '/opt/pydmon.log'
        log_file = open(filepath,'a')
        try:
            log_file.write(time.ctime()+"\n")
        finally:
            log_file.close()
            time.sleep(10)

def daemonize():
    pid = os.fork()#ここでプロセスをforkする
    if pid > 0:#親プロセスの場合(pidは子プロセスのプロセスID)
        pid_file = open('/var/run/python_daemon.pid','w')
        pid_file.write(str(pid)+"\n")
        pid_file.close()
        sys.exit()
    if pid == 0:#子プロセスの場合
        main_unit()

if __name__ == '__main__':
    while True:
        daemonize()

Shebangを指定しましょう。

先頭に#!/usr/bin/env python#!/usr/bin/pythonを加えます。
#!/usr/bin/env python$PATHの先頭にあるpythonを優先して使うそうです。
対して、#!/usr/bin/pythonは直接/usr/bin/配下にあるpythonを指定しているらしい。
バージョンが違うと不都合がおきるかもしれないです。

Stack overflowに詳しいことがありましたので、興味の有る方は参考にしてみてください。
Why do people write #!/usr/bin/env python on the first line of a Python script?

daemonize()について

プロセスをforkして、親プロセスは変数pidに返った子プロセスIDをpidファイルに書き込んで消えます。
一方、子プロセスはmain_unit()を10秒おきに無限ループで実行します。

保存したら実行権限を与えましょう。

sudo chmod 755 /opt/python_daemon.py
これで実行権限が付与されたはずです。

ユニット定義ファイルを作る

/usr/lib/systemd/system/pythondaemon.service
[Unit]
Description=PythonDaemon

[Service]
ExecStart=/opt/python_daemon.py
Restart=always
Type=forking
PIDFile=/var/run/python_daemon.pid

[Install]
WantedBy=multi-user.target

Daemonの定義ファイルです。
ExecStartとPIDFileが帳尻合えばあとはコピペでも大丈夫かと思います。

デーモンを起動する

sudo systemctl daemon-reload
sudo systemctl start pythondaemon.service

デーモンをリロードしたら、新しく作ったpythondaemon.serviceが認識されます。
そしてstartで起動させます。

結果

$ sudo systemctl status pythondaemon.service


● pythondaemon.service - PythonDaemon
   Loaded: loaded (/usr/lib/systemd/system/pythondaemon.service; disabled; vendor preset: disabled)
   Active: active (running) since 月 2017-09-11 00:35:12 JST; 10s ago
  Process: 4633 ExecStart=/opt/python_daemon.py (code=exited, status=0/SUCCESS)
 Main PID: 4634 (python)
   CGroup: /system.slice/pythondaemon.service
           └─4634 python /opt/python_daemon.py

うごいた!

pydmon.logもこんな感じ

$ cat pydmon.log 
Mon Sep 11 00:35:12 2017
Mon Sep 11 00:35:22 2017
Mon Sep 11 00:35:32 2017
Mon Sep 11 00:35:42 2017
Mon Sep 11 00:35:52 2017
Mon Sep 11 00:36:02 2017
Mon Sep 11 00:36:12 2017
Mon Sep 11 00:36:22 2017
Mon Sep 11 00:36:32 2017
Mon Sep 11 00:36:42 2017
Mon Sep 11 00:36:52 2017
Mon Sep 11 00:37:02 2017

感想

systemctlで管理ができるので楽ちんだし、何か感動する