Supervisorによるプロセス管理

Linux/Unixのプロセスを管理するpython製のOSSであるSupervisorを使っているソフトウェアに触れる機会があったのですが、あまり知識がなかったのでSupervisorについて調べてまとめてみました。
目次
Supervisorについて
- Linux/Unixのプロセスを管理するソフトウェアでPythonで開発されている。
- クライアント/サーバー型である。
- Python3の環境においてはdo not work[1]Supervirord4.0は、Python 2.6以上、Python 3.2以上で動作させられるよう計画されているとされており、Python2の環境での利用が推奨されている。
(2016/11/10現在、githubのOverviewより) - Windows環境はサポートされていない。
- init(Process id 1)の代替ではない。
- プロセスがクラッシュした時、リスタートしてくれる。
- プロセスを自身のサブプロセスとして実行するので、Pidfileのようなプロセスの実態との不一致がない。
- サブプロセスをdaemon化しない。
- プロセスをグループで管理することができ、”start all”や”restart all”のようにグループに対してコマンドを実行してくれる。
- ShellやWebUIからプロセスの状態をコントロールでき、またXML-RPCインターフェースを持っている。
- 十分に枯れている。
supervisorを使っているソフトウェアとして、私が触れたことがある例では、HadoopディストリビューションCDHの管理ソフトウェアであるClouderaManager[2]http://www.cloudera.com/products/cloudera-manager.htmlがあります。
Supervisorを構成するコンポーネント
Supervisorを構成しているコンポーネントは以下。
supervisord
子プロセスをコントロールするサーバープロセス。設定ファイルは、/etc/supervisord.conf
でINI形式[3]https://en.wikipedia.org/wiki/INI_fileで記述する。
supervisorctl
クライアントプログラム。UnixドメインソケットやTCPソケット経由でsupervisordと対話する。
設定は、[supervisorctl]
セクションに記述する。
Web Server
supervisorctlの機能をブラウザ経由で実行できるWebインターフェース。
設定は、[inet_http_server]
セクションに記述する。
インストール
pythonがインストールされていない場合は、まずpythonをインストールする必要がある。あとはsetuptoolsまたはpipでインストールできる。
# using easy_install $ easy_install supervisor # or using pip $ pip install supervisor
ディストリビューションのパッケージの場合、例えばCentOSではyumでいける。以下はepel経由でインストールしている。
yum install -y --enablerepo=epel supervisor
以下のecho_supervisord_conf
コマンドで設定ファイルのsampleを確認でき、このテンプレートをベースに設定を記述していくことができる。
$ echo_supervisord_conf ; Sample supervisor config file. ; ; For more information on the config file, please see: ; http://supervisord.org/configuration.html ; ; Notes: ; - Shell expansion ("~" or "$HOME") is not supported. Environment ; variables can be expanded using this syntax: "%(ENV_HOME)s". ; - Comments must have a leading space: "a=b ;comment" not "a=b;comment". [unix_http_server] file=/tmp/supervisor.sock ; (the path to the socket file) ;chmod=0700 ; socket file mode (default 0700) ;chown=nobody:nogroup ; socket file uid:gid owner ;username=user ; (default is no username (open server)) ;password=123 ; (default is no password (open server)) ;[inet_http_server] ; inet (TCP) server disabled by default ;port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface) ;username=user ; (default is no username (open server)) ;password=123 ; (default is no password (open server)) [supervisord] logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log) logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB) logfile_backups=10 ; (num of main logfile rotation backups;default 10) loglevel=info ; (log level;default info; others: debug,warn,trace) pidfile=/tmp/supervisord.pid ; (supervisord pidfile;default supervisord.pid) nodaemon=false ; (start in foreground if true;default false) minfds=1024 ; (min. avail startup file descriptors;default 1024) minprocs=200 ; (min. avail process descriptors;default 200) ;umask=022 ; (process file creation umask;default 022) ;user=chrism ; (default is current user, required if root) ;identifier=supervisor ; (supervisord identifier, default is 'supervisor') ;directory=/tmp ; (default is not to cd during start) ;nocleanup=true ; (don't clean up tempfiles at start;default false) ;childlogdir=/tmp ; ('AUTO' child log dir, default $TEMP) ;environment=KEY="value" ; (key value pairs to add to environment) ;strip_ansi=false ; (strip ansi escape codes in logs; def. false) ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be ; added by defining them in separate rpcinterface: sections [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket ;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket ;username=chris ; should be same as http_username if set ;password=123 ; should be same as http_password if set ;prompt=mysupervisor ; cmd line prompt (default "supervisor") ;history_file=~/.sc_history ; use readline history if available ; The below sample program section shows all possible program subsection values, ; create one or more 'real' program: sections to be able to control them under ; supervisor. ;[program:theprogramname] ;command=/bin/cat ; the program (relative uses PATH, can take args) ;process_name=%(program_name)s ; process_name expr (default %(program_name)s) ;numprocs=1 ; number of processes copies to start (def 1) ;directory=/tmp ; directory to cwd to before exec (def no cwd) ;umask=022 ; umask for process (default None) ;priority=999 ; the relative start priority (default 999) ;autostart=true ; start at supervisord start (default: true) ;startsecs=1 ; # of secs prog must stay up to be running (def. 1) ;startretries=3 ; max # of serial start failures when starting (default 3) ;autorestart=unexpected ; when to restart if exited after running (def: unexpected) ;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2) ;stopsignal=QUIT ; signal used to kill process (default TERM) ;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10) ;stopasgroup=false ; send stop signal to the UNIX process group (default false) ;killasgroup=false ; SIGKILL the UNIX process group (def false) ;user=chrism ; setuid to this UNIX account to run the program ;redirect_stderr=true ; redirect proc stderr to stdout (default false) ;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO ;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) ;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10) ;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0) ;stdout_events_enabled=false ; emit events on stdout writes (default false) ;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO ;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) ;stderr_logfile_backups=10 ; # of stderr logfile backups (default 10) ;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0) ;stderr_events_enabled=false ; emit events on stderr writes (default false) ;environment=A="1",B="2" ; process environment additions (def no adds) ;serverurl=AUTO ; override serverurl computation (childutils) ; The below sample eventlistener section shows all possible ; eventlistener subsection values, create one or more 'real' ; eventlistener: sections to be able to handle event notifications ; sent by supervisor. ;[eventlistener:theeventlistenername] ;command=/bin/eventlistener ; the program (relative uses PATH, can take args) ;process_name=%(program_name)s ; process_name expr (default %(program_name)s) ;numprocs=1 ; number of processes copies to start (def 1) ;events=EVENT ; event notif. types to subscribe to (req'd) ;buffer_size=10 ; event buffer queue size (default 10) ;directory=/tmp ; directory to cwd to before exec (def no cwd) ;umask=022 ; umask for process (default None) ;priority=-1 ; the relative start priority (default -1) ;autostart=true ; start at supervisord start (default: true) ;startsecs=1 ; # of secs prog must stay up to be running (def. 1) ;startretries=3 ; max # of serial start failures when starting (default 3) ;autorestart=unexpected ; autorestart if exited after running (def: unexpected) ;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2) ;stopsignal=QUIT ; signal used to kill process (default TERM) ;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10) ;stopasgroup=false ; send stop signal to the UNIX process group (default false) ;killasgroup=false ; SIGKILL the UNIX process group (def false) ;user=chrism ; setuid to this UNIX account to run the program ;redirect_stderr=false ; redirect_stderr=true is not allowed for eventlisteners ;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO ;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) ;stdout_logfile_backups=10 ; # of stdout logfile backups (default 10) ;stdout_events_enabled=false ; emit events on stdout writes (default false) ;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO ;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB) ;stderr_logfile_backups=10 ; # of stderr logfile backups (default 10) ;stderr_events_enabled=false ; emit events on stderr writes (default false) ;environment=A="1",B="2" ; process environment additions ;serverurl=AUTO ; override serverurl computation (childutils) ; The below sample group section shows all possible group values, ; create one or more 'real' group: sections to create "heterogeneous" ; process groups. ;[group:thegroupname] ;programs=progname1,progname2 ; each refers to 'x' in [program:x] definitions ;priority=999 ; the relative start priority (default 999) ; The [include] section can just contain the "files" setting. This ; setting can list multiple files (separated by whitespace or ; newlines). It can also contain wildcards. The filenames are ; interpreted as relative to this file. Included files *cannot* ; include files themselves. ;[include] ;files = relative/directory/*.ini
supervisordの起動
以下でsupervisordのプロセスを起動する。
supervisord [options]
supervisordのコマンドラインオプション
-c FILE
- 設定ファイルを指定。
-n, –nodaemon
- デーモン化しない、foregroundで動作させる。
- デフォルトでは、daemonで動作する。
-h, –help
- ヘルプを表示する。
-u USER, –user=USER
- プロセスownerをUSERにする。USERには、usernameまたはuser idを指定する。
-m OCTAL, –umask=OCTAL
- supervisordが使うデフォルトマスク。例:022
- デフォルトは、
022
。
-d PATH, –directory=PATH
- supervisordがdaemonとして実行されるときにcdするPATH。
-l FILE, –logfile=FILE
- ログファイル。
- デフォルトで、
$CWD/supervisord.log
。
-y BYTES, –logfile_maxbytes=BYTES
- ログファイルを指定されたBYTES(byte)でローテートする。
- デフォルトで、
50MB
。 - 例:1 = 1 byte、1M = 1 000 000 bytes、1G = 1 000 000 000 bytes
-y NUM, –logfile_backups=NUM
- ログファイルがバックアップされる世代数。
- デフォルトで、
10
。
-e LEVEL, –loglevel=LEVEL
- ログレベル。例:trace、debug、info、warn、error、critical
- デフォルトで、
info
。
-j FILE, –pidfile=FILE
- pidを書くファイル。
- デフォルトで、
$CWD/supervisord.pid
。
-i STRING, –identifier=STRING
- 現在のsupervisorインスタンスを識別できる任意の文字列。
- デフォルトは、
supervisor
。
-q PATH, –childlogdir=PATH
- AUTO指定の子プロセスのログディレクトリ。
-k, –nocleanup
- 起動時にAUTO指定の子プロセスのログを削除しない。
-a NUM, –minfds=NUM
- supervisordの利用可能なファイル記述子の上限(
RLIMIT_NOFILE
)を設定する。 - NUMがhard limitを超える場合、hard = NUMとなる。
- デフォルトは、
1024
。
-t, –strip_ansi
- 子プロセスのログからANSIエスケープシーケンス文字を除去する。
-v, –version
- バージョンを表示する。
–profile_options=LIST
- プロファイルのためのオプションリストをカンマ区切りで指定する。supervisordはプロファイラの下で動作する。
- 例:cumulative、calls、callers
–minprocs=NUM
- supervisordのプロセス生成数の上限(
RLIMIT_NPROC
)を設定する。 - NUMがhard limitを超える場合は、NUM = hardとなる。
- デフォルトは、
200
。
自動起動設定
以下に各種Linux/Unixディストリビューションのinitスクリプトを公開してくれているので、環境に合わせてダウンロードして設置する。
https://github.com/Supervisor/initscripts
supervisorctlの実行
supervisorctlはコマンドラインツールで、supervisordに接続してプロセスの各種コントロール要求を送る。
supervisorctl [options] [action [arguments]]
supervisorctlのコマンドラインオプション
-c, –configuration
- 設定ファイルを指定する。
- デフォルトは、
/etc/supervisord.conf
。
-h, –help
- ヘルプを表示する。
-i, –interactive
- 対話モードで起動する。
- 引数なしでコマンドを実行するとpromptが起動する。
-s, –serverurl URL
- 接続するサーバープロセス(supervisord)のURL。
- デフォルトで、
http://localhost:9001/
。
-u, –username
- ユーザー認証のユーザー名。
-p, –password
- ユーザー認証のパスワード。
-r, –history-file
- 操作履歴を保持する(readlineがある場合)
コマンド例
### status # 管理下のプロセスのステータスを確認 supervisorctl status ### start # sampleプロセスを起動 supervisorctl start sample ### restart # sampleプロセスを再起動 supervisorctl restart sample # すべてのプロセスを再起動 supervisorctl restart all ### tail # sampleプロセスのログを追尾する supervisorctl tail -f sample ### stop # sampleプロセスを停止 supervisorctl stop sample ### remove # sampleプロセスを非アクティブ化 supervisorctl remove sample ### add # sampleプロセスをアクティブ化 supervisorctl add sample ### fg # sampleプロセスにフォアグランドで接続 supervisorctl fg sample ### reload # supervisordを再起動 supervisorctl reload ### reread # 設定をリロード supervisorctl reread ### shutdown # supervisordをshutdown supervisorctl shutdown
サンプルプログラムをsupervisordで実行してみる
まずは、簡単なサンプルプログラムを用意しsupervisor管理下で実行してみる。
supervisord.conf
設定はとりあえず最小限で以下のとおり。
[inet_http_server] port=127.0.0.1:9001 username=user password=password [supervisord] [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] username=user password=password [program:sample] command=/bin/sh /path/to/hello.sh process_name=%(program_name)s stdout_logfile=hello.log
commandのhello.shは以下。
#!/usr/bin/env bash i=0 while true; do printf "hello = %d\n" $i let i=i+1 sleep 1 done
以上を準備し、supervisordをforegroundで起動してみる。
$ supervisord --nodaemon 2016-11-12 21:05:40,078 INFO Increased RLIMIT_NOFILE limit to 1024 2016-11-12 21:05:40,086 INFO RPC interface 'supervisor' initialized 2016-11-12 21:05:40,087 INFO RPC interface 'supervisor' initialized 2016-11-12 21:05:40,087 CRIT Server 'unix_http_server' running without any HTTP authentication checking 2016-11-12 21:05:40,087 INFO supervisord started with pid 15347 2016-11-12 21:05:41,094 INFO spawned: 'sample' with pid 15350 2016-11-12 21:05:42,105 INFO success: sample entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
supervisordのWebUIでプロセス管理
上記実行後、127.0.0.1:9001でHTTPサーバーが起動しており、以下にアクセスするとWebUIを確認できる。なお、アクセス時に認証を要求されるが、confで設定したuserとpasswordを指定すればよい。
上記では、プログラム名「sample」がrunning
状態となっており、sampleのリンクやTail -fをクリックすると以下のような出力を確認できる。また、プロセス単体及びプロセスをまとめて起動・停止を行なうことができる。
supervisorctlでsupervisordに接続
続いてsupervisorctlでアクセスしてみる。help
コマンドでコマンドリストが表示される。help <command>
でコマンド詳細を確認できる。
$ supervisorctl sample RUNNING pid 17832, uptime 0:01:31 supervisor> status sample RUNNING pid 17832, uptime 0:01:52 supervisor> help default commands (type help <topic>): ===================================== add exit open reload restart start tail avail fg pid remove shutdown status update clear maintail quit reread signal stop version supervisor> help status status <name> Get status for a single process status <gname>:* Get status for all processes in a group status <name> <name> Get status for multiple named processes status Get all process status info
ここでは、先ほどのsampleプログラムを停止してみる。stopでプロセス名を指定しないとusageが表示される。続いてプロセス名を正しく指定して、stopコマンドを実行すると停止できる。
supervisor> stop Error: stop requires a process name stop <name> Stop a process stop <gname>:* Stop all processes in a group stop <name> <name> Stop multiple processes or groups stop all Stop all processes supervisor> stop sample sample: stopped
WebUIでrunning
となっていたプロセスのステータスもstopped
になっていることを確認できる。
プロセスが異常終了した場合
もしプロセスが何らかの理由でダウンした場合、デフォルトの設定では再度プロセスを開始する。killコマンドでSIGTERMを送ってみる。
2016-11-27 11:00:50,319 INFO exited: sample (terminated by SIGTERM; not expected) 2016-11-27 11:00:51,077 INFO spawned: 'sample' with pid 8563 2016-11-27 11:00:52,081 INFO success: sample entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
続いてSIGSEGVを送ってみる。
2016-11-27 11:06:07,606 INFO exited: sample (terminated by SIGSEGV; not expected) 2016-11-27 11:06:07,723 INFO spawned: 'sample' with pid 9243 2016-11-27 11:06:08,728 INFO success: sample entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
予期せぬ異常終了時にもプロセスがリスタートされていることを確認できた。ただ、本来はプロセスが異常終了しないように根本原因を特定し問題を解決する必要があるだろう。
プロセスを開始できなかった(終了する)場合
仮にプロセスが開始できなかった場合、リトライ回数の上限まで起動を試みた後fatal
状態になる。
試しにスクリプトをexitstaus 0
で終了させてみる。
#!/usr/bin/env bash # i=0 while false; do printf "hello = %d\n" $i let i=i+1 sleep 1 done
ログには以下のように出力された。
2016-11-27 15:10:12,856 INFO Increased RLIMIT_NOFILE limit to 1024 2016-11-27 15:10:12,863 INFO RPC interface 'supervisor' initialized 2016-11-27 15:10:12,864 INFO supervisord started with pid 23659 2016-11-27 15:10:13,867 INFO spawned: 'sample' with pid 23662 2016-11-27 15:10:13,875 INFO exited: sample (exit status 0; not expected) 2016-11-27 15:10:14,877 INFO spawned: 'sample' with pid 23663 2016-11-27 15:10:14,884 INFO exited: sample (exit status 0; not expected) 2016-11-27 15:10:16,887 INFO spawned: 'sample' with pid 23664 2016-11-27 15:10:16,894 INFO exited: sample (exit status 0; not expected) 2016-11-27 15:10:19,904 INFO spawned: 'sample' with pid 23665 2016-11-27 15:10:19,910 INFO exited: sample (exit status 0; not expected) 2016-11-27 15:10:20,915 INFO gave up: sample entered FATAL state, too many start retries too quickly
数回リトライした後FATAL
状態に移行し、プロセス開始が停止されたことを確認できる。
以上サンプルプログラムをsupervisor経由で実行し、supervisorでプロセス管理するイメージを掴むことができた。運用ではsupervisord自体の監視が必要になるだろう。
supervisordのシグナルハンドリング
supervisordがハンドリングするシグナルには以下のようなものがある。
TERM、INT、QUIT
supervisordとそのすべての子プロセスをshutdownする。以下はSIGTERMを送った例。
kill -s TERM $(supervisorctl pid)
シグナルを受信したsupervisordは以下のようなログを出力する。
2016-11-14 15:51:08,677 WARN received SIGTERM indicating exit request 2016-11-14 15:51:08,677 INFO waiting for sample to die 2016-11-14 15:51:08,677 INFO stopped: sample (terminated by SIGTERM)
HUP
すべての子プロセスを停止し設定をリロード、続いてプロセスを開始する。
kill -s HUP $(supervisorctl pid)
シグナルを受信したsupervisordは以下のようなログを出力する。
2016-11-14 15:59:07,283 WARN received SIGHUP indicating restart request 2016-11-14 15:59:07,283 INFO waiting for sample to die 2016-11-14 15:59:07,284 INFO stopped: sample (terminated by SIGTERM) 2016-11-14 15:59:07,291 INFO supervisord started with pid 30326 2016-11-14 15:59:08,295 INFO spawned: 'sample' with pid 30337 2016-11-14 15:59:09,306 INFO success: sample entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
USR2
メインとすべての子プロセスのログを再オープンする。
kill -s USR2 $(supervisorctl pid)
シグナルを受信したsupervisordは以下のようなログを出力する。
2016-11-14 16:04:22,491 INFO received SIGUSR2 indicating log reopen request 2016-11-14 16:04:22,491 INFO supervisord logreopen
supervisord.conf
supervisord関連の設定はこのconfに記述していくことになる。読み込みの優先順位や主なセクションについてまとめる。詳細は、本家の公式ドキュメントまたはソースのoptions.pyを参照のこと。
設定ファイルの優先順位
設定ファイルは、以下の順で探索される。
- <supervisor_bindir>/etc/supervisord.conf
- <supervisor_bindir>/supervisord.conf
- supervisord.conf
- etc/supervisord.conf
- /etc/supervisord.conf
- /etc/supervisor/supervisord.conf’
[unix_http_server]セクション
UnixドメインソケットでlistenするHTTPサーバーの設定。
項目 | 説明 | デフォルト |
---|---|---|
file | socketのファイルのパス | None |
chmod | fileのパーミッション | 0700 |
chown | fileのuserとgroup 例: supervisord:supervisord |
supervisordを開始したuserとgroup |
username | HTTPサーバー認証で使うuser | None |
password | HTTPサーバー認証で使うpassword クリアテキストまたはsha-1 Basic認証で聞かれる |
None |
[inet_http_server]セクション
TCPソケットでlistenするHTTPサーバーの設定。
項目 | 説明 | デフォルト |
---|---|---|
port | listenするhost:port。 例1:ローカルアドレスで指定 127.0.0.1:9001 例2:ワイルドカードバインドで指定 *:9001 |
None |
username | HTTPサーバー認証で使うuser | None |
password | HTTPサーバー認証で使うpassword クリアテキストまたはsha-1 Basic認証で聞かれる |
None |
[supervisord]セクション
supervisordプロセスに関する設定。
項目 | 説明 | デフォルト |
---|---|---|
logfile | ログファイルのパス | $CWD/supervisord.log |
logfile_maxbytes | ログファイルの最大サイズ | 50MB |
logfile_backups | ログファイルを保持する世代数0 を指定すると保持されない |
10 |
loglevel | ログレベル | info |
pidfile | プロセスIDが記録されるファイルパス | $CWD/supervisord.pid |
umask | supervisordプロセスのumask | 022 |
nodaemon | デーモン化するかしないかtrue の場合、foregroundで動作する |
false |
minfds | ファイル記述子の上限を変更する(RLIMIT_NOFILE)[4]http://docs.python.jp/2/library/resource.html | 1024 |
minprocs | プロセス生成数の上限を変更する(RLIMIT_NOPROC)[5]http://docs.python.jp/2/library/resource.html | 200 |
nocleanup | 起動時にAUTO指定の子プロセスのログのクリーンアップをしない | false |
childlogdir | AUTO指定の子プロセスのログファイルを作成するディレクトリ | tempfile.get_tempdir() |
user | supervisordがスイッチするuser | None |
directory | supervisordがdaemon時にスイッチするディレクトリ | None |
strip_ansi | 子プロセスのログファイルからANSIエスケープシーケンスを除去する | false |
environment | supervisordに渡される環境変数(子プロセスにも引き継がれる) | None |
identifier | supervisordインスタンスの識別子 | supervisor |
[supervisorctl]セクション
項目 | 説明 | デフォルト |
---|---|---|
serverurl | supervisordサーバーのURL | http://localhost:9001 |
username | HTTPサーバー認証のユーザー名 | None |
password | HTTPサーバー認証のパスワード | None |
prompt | promptで使われる文字列 例: %(ENV_USER)s |
supervisor |
history_file | supervisorctlのコマンド履歴ファイル | None |
例:history_fileを指定
[supervisorctl] history_file = supervisorctl_history
status、help、restartとコマンド実行して見た結果、以下の履歴が保存される。
$ cat supervisorctl_history status help restart sample
[program:x]セクション
supervisord管理下で動作させるプログラムの設定。x
にはプログラムを識別する任意の文字列を指定する。
項目 | 説明 | デフォルト |
---|---|---|
command | プログラムの実行コマンド | None |
process_name | プログラム名。numprocsが1より大きい場合は、process_num指定が必要 例: %(program_name)s_%(process_num)02d |
%(program_name)s |
numprocs | プロセス数 | 1 |
numprocs_start | プロセス数のオフセット値 例:numprocs = 2、numprocs_start = 2の場合 %(process_num)02d は、02 、03 となる。 |
0 |
priority | 起動、停止における優先度。値が小さいほど優先度が高い | 999 |
autostart | 自動起動設定 | true |
startsecs | RUNNING状態とみなすまでの秒数 | 1 |
startretries | 起動のリトライ回数 | 3 |
autorestart | 予期せぬ終了時の再起動設定unexpected :RUNNING状態でexitcodesで終了すると自動再起動true :exitcodesに関わらず自動再起動 |
unexpected |
exitcodes | autorestartオプションのunexpected で使われる終了コード。このリストにない終了コードでプロセスが終了した場合、自動再起動がかかる。 |
0,2 |
stopsignal | プロセス停止に使われるシグナル | TERM |
stopwaitsecs | プロセスにstopsignalが送られた後、OSがSIGCHILDをsupervisordに戻すのに待つ時間(秒) | 10 |
stopasgroup | プロセスグループに対してstopsignalを送信する。この値がfalse の場合。サブプロセスが実行されている場合はリペアレンティングされる。 |
false |
killasgroup | プロセスグループに対してSIGKILLを送信する。デフォルトでは、stopasgroupと同じ値となる。 | false |
user | supervisordがプログラムを実行するときにスイッチするuser | – |
redirect_stderr | true の場合、プロセスの標準エラー出力は標準出力にリダイレクトされる。 |
false |
stdout_logfile | プロセスの標準出力が記録されるファイル | AUTO |
stdout_logfile_maxbytes | stdout_logfileのファイルサイズ上限 | 50MB |
stdout_logfile_backups | stdout_logfileが保存される世代数 | 10 |
stdout_capture_maxbytes | プロセスがstdout capture modeの時、FIFOをキャプチャする最大バイト数 | 0 |
stdout_events_enabled | trueの場合、プロセスがstdoutに書き込む時にPROCESS _LOG_STDOUT イベントが送られる。 |
0 |
stderr_logfile | プロセスの標準エラー出力が記録されるファイル | AUTO |
stderr_logfile_maxbytes | stderr_logfileのファイルサイズ上限 | 50MB |
stderr_logfile_backups | stderr_logfileが保存される世代数 | 10 |
stderr_capture_maxbytes | プロセスがstderr capture modeの時、FIFOをキャプチャする最大バイト数 | 0 |
stderr_events_enabled | trueの場合、プロセスがstderrに書き込む時にPROCESS _LOG_STDOUT イベントが送られる。 |
false |
environment | プロセスに引き継がれる環境変数 例:environment = HOGE=”foo” |
None |
directory | supervisordがプロセスを起動する時にchdirするディレクトリのパス | supervisorのものを継承 |
umask | プロセスのumask | supervisorのものを継承 |
serverurl | プロセスと対話するサーバーURL プロセス中では、環境変数で SUPERVISOR_SERVER_URL として参照できる。 |
AUTO |
[group:x]セクション
項目 | 説明 | デフォルト |
---|---|---|
programs | グループに属するプログラムをカンマ区切りで記述する | None |
priority | 優先度 | 999 |
その他にも設定項目がありますが疲れたのでここで。。
stopasgroupオプションの動作について確認
stopasgroupオプションはデフォルトでfalse
だが、true
にした状態でプロセスからサブプロセスを実行して親プロセスにシグナルを送出してみる。
#!/usr/bin/env bash i=0 function handle_signal() { echo "*** signal trapped ***" # kill $CPID exit 0 } function exec_process() { local pname="$1" while true; do printf "$pname: hello = %d\n" $i echo $SUPERVISOR_SERVER_URL let i=i+1 sleep 1 done } trap "handle_signal" SIGTERM PID=$$ echo "parent pid: $PID" exec_process "child-1" & CPID=$! echo "child pid: $CPID" exec_process "parent"
続いて、supervisord.confを以下のようにする。
[program:sample2] command=/bin/sh /tmp/hello-child.sh process_name=%(program_name)s stdout_logfile=hello2-stdout.log stderr_logfile=hello2-stderr.log stopasgroup = true
supervisordを起動する。
$ supervisord
プロセスツリーを確認する。
$ pstree | grep [h]ello | \-+= 52797 guest /bin/sh /tmp/hello-child.sh | |-+- 52798 guest /bin/sh /tmp/hello-child.sh
サププロセスとして実行されていることを確認できる。続いて、supervisorctlからstopコマンドでSIGTERMを送る。
$ supervisorctl stop sample2
pstreeでgrepしても確認できないので、親・子プロセスとも停止している。
続いて、stopasgroup = false
にして実行して同様な操作をしてみたところ以下のようにリペアレンティングされていることを確認できる。
$ pstree | grep [h]ello |-+- 52960 guest /bin/sh /tmp/hello-child.sh
supervisorctl stop
でなく端末からシグナルを送ってみる。最初の状態は以下。
$ pstree | grep [h]ello | \-+= 53171 guest /bin/sh /tmp/hello-child.sh | |-+- 53172 guest /bin/sh /tmp/hello-child.sh
続いてSIGTERMを送る。
$ kill -s TERM 53171
親プロセスは変わっていることを確認できる。
$ pstree | grep [h]ello |-+- 53172 guest /bin/sh /tmp/hello-child.sh
参考リンク
- Supervisor Documents
- Supervisor Repository
- Other useful web sites
売り上げランキング: 40,034
脚注
↑1 | Supervirord4.0は、Python 2.6以上、Python 3.2以上で動作させられるよう計画されている |
↑2 | http://www.cloudera.com/products/cloudera-manager.html |
↑3 | https://en.wikipedia.org/wiki/INI_file |
↑4, ↑5 | http://docs.python.jp/2/library/resource.html |