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スクリプトのデーモン化の方法についてまとめました。