【Python】Supervisorによるスクリプトのデーモン化

Supervisorは、UNIX-likeオペレーティング・システム上でプロセス管理を可能にするクライアント/サーバシステムです。Pythonスクリプトを簡単にデーモン化することができます。
今回は、このモジュールの使いかたの基本についてまとめます。

環境

  • OS: Ubuntu16.04LTS およびUbntu18.04LTS
  • Python3.7.2@Anaconda
  • Supervisor 3.2.0

デーモン(daemon)とは

Wikipediaから引用します。

デーモン (英語: Daemon) は、UNIX, Linux, MacOSXなどUnix系のマルチタスクオペレーティングシステム (OS) において動作するプロセス(プログラム)で、主にバックグラウンドで動作するプロセス[1]。ユーザが直接対話的に制御するプログラムもデーモンとして作ることができる[2]。典型的なデーモンは名前の最後尾に “d” が付く。

Wikipedia デーモン (ソフトウェア)

※末尾のdはdaemonのdだったのは初めて知りました。

デーモン化の方法

プログラムのデーモン化はいくつか方法があります。

  • systemdを使う方法
  • supervisorを使う方法
  • python-deamonモジュールを使う方法

本記事では、supervisorを使った方法についてまとめます。

Supervisorのインストール

aptコマンドでインストールできます。

$ sudo apt install supervisor

バージョンを確認

$ supervisord -v
3.2.0

この場合/etc/supervisorディレクトリに格納されます。ファイル構成はこんなかんじ。

@ubuntu:/etc/supervisor$ tree
      .
      ├── conf.d
      └── supervisord.conf

conf.dフォルダにデーモン化したいスクリプトの情報を記述しconfファイルとして格納します。

supervisord.confは普通に使う分には特に変更はいらないと思います。
但し、supervisor自身のログ出力先を変えたい場合などはsupervisord.confの下記記述部を変更します。

[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor            ; ('AUTO' child log dir, default $TEMP)

尚、

pip install supervisor

でもインストールできますが、格納場所が異なるので注意です。

.confファイルを作成

スクリプトをデーモン化するためのプロセスの情報を記述します。格納場所は以下。
例としてファイル名はmyapp.confとしました。

$ vim /etc/supervisor/conf.d/myapp.conf

confファイルの記述例を以下に示します。

[program:myapp]
directory=/home/hibikisan/projects/app
command=/home/hibikisan/projects/app/py37/bin/python /home/hibikisan/projects/app/test.py
autostart=true
autorestart=true
user=hibikisan
stdout_logfile=/var/log/supervisor/myapp.log
redirect_stderr=true

パラメータそれぞれの意味を以下に示します。

パラメータ 説明
directory 実行ファイルのパス
command スクリプトを実行するコマンド。絶対パスでも相対パスでも可。相対パスの場合は、supervisordの環境変数$PATHが検索される。
autostart supervisordが起動するときに自動でプログラムを開始する場合はTrue
autorestart supervisordが終了した時に、supervisordがプロセスを自動的に再起動させる場合はTrue
user プログラムを起動するユーザーアカウント
stdout_logfile 標準出力の結果を出力するファイルパス
redirect_stderr 標準エラー出力をstdout_logfileに出力する場合はTrue

詳細は、公式リファレンス を参照ください。

Supervisorを起動

まずはsupervisor自身を起動する

$ sudo service supervisor restart

statusを確認

$ sudo service supervisor status
● supervisor.service - Supervisor process control system for UNIX
   Loaded: loaded (/lib/systemd/system/supervisor.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2019-09-23 22:47:28 JST; 12min ago
      Docs: http://supervisord.org
   Process: 23052 ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown (code=exited, status=0/SUCCESS)
   Main PID: 23053 (supervisord)
      Tasks: 2 (limit: 1996)
   CGroup: /system.slice/supervisor.service
            ├─23053 /usr/bin/python /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf
            └─23075 /home/hibikisan/projects/app/py37/bin/python /home/hibikisan/projects/app/test.py
            :
            :

プロセスの起動、再起動、stasutの確認

confファイルを読み込む(変更した場合はこれを実行)

$ sudo supervisorctl reread
myapp: changed

プロセスを開始する

$ sudo supervisorctl start myapp
myapp: started

プロセスを再起動する

$ sudo supervisorctl restart myapp
myapp: stopped
myapp: started

statusを確認

$ sudo supervisorctl status myapp
myapp                            RUNNING   pid 26808, uptime 0:08:49

プロセスを停止する

$ sudo supervisorctl stop myapp
myapp: stopped

ログの確認

  • Supervisorのログ
  • /var/log/supervisor.logで確認できます。

    $ vim /var/log/supervisor/supervisord.log
          
          2019-09-23 22:47:28,842 INFO waiting for myapp to die
          2019-09-23 22:47:28,866 INFO stopped: myapp (terminated by SIGTERM)
          2019-09-23 22:47:29,125 CRIT Supervisor running as root (no user in config file)
          2019-09-23 22:47:29,126 INFO Included extra file "/etc/supervisor/conf.d/myapp.conf" during parsing
          2019-09-23 22:47:29,148 INFO RPC interface 'supervisor' initialized
          2019-09-23 22:47:29,149 CRIT Server 'unix_http_server' running without any HTTP authentication checking
          2019-09-23 22:47:29,149 INFO supervisord started with pid 23053
          2019-09-23 22:47:30,203 INFO spawned: 'myapp' with pid 23075
          2019-09-23 22:47:31,206 INFO success: myapp entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
                :
                :
  • プロセスのログ
  • Pythonスクリプト中で記述した標準出力は/etc/supervisor/conf.d/myapp.confで設定したlogファイルに出力されます。

    $ vim /var/log/supervisor/myapp.log

    (参考)
    Pythonスクリプト中のprint()でうまく出力されない場合は、下記の通りsys.stdoutを使うと上手く行くかも。

    dt = datetime.datetime.now()
    time_stamp = dt.strftime('%Y年%m月%d日 %H時%M分%S秒')
    sys.stdout.write(f"{time_stamp}: {data1}, {data2}\n")
    sys.stdout.flush()

まとめ

Supervisorを使ったPythonスクリプトのデーモン化の方法についてまとめました。

Learn more...

書籍でもう少し詳しく学びたい場合はこちらもどうぞ。筆者もかなり参考にさせてもらっています!

[Sponsor link]