Supervisorによるプロセス管理

supervisor
この記事は約20分で読めます。

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でインストールできる。

ディストリビューションのパッケージの場合、例えばCentOSではyumでいける。以下はepel経由でインストールしている。

以下のecho_supervisord_confコマンドで設定ファイルのsampleを確認でき、このテンプレートをベースに設定を記述していくことができる。

supervisordの起動

以下でsupervisordのプロセスを起動する。

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スクリプトを公開してくれているので、環境に合わせてダウンロードして設置する。

GitHub - Supervisor/initscripts: User-contributed OS init scripts for Supervisor
User-contributed OS init scripts for Supervisor. Contribute to Supervisor/initscripts development by creating an account...

supervisorctlの実行

supervisorctlはコマンドラインツールで、supervisordに接続してプロセスの各種コントロール要求を送る。

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がある場合)

コマンド例

サンプルプログラムをsupervisordで実行してみる

まずは、簡単なサンプルプログラムを用意しsupervisor管理下で実行してみる。

supervisord.conf

設定はとりあえず最小限で以下のとおり。

commandのhello.shは以下。

以上を準備し、supervisordをforegroundで起動してみる。

supervisordのWebUIでプロセス管理

上記実行後、127.0.0.1:9001でHTTPサーバーが起動しており、以下にアクセスするとWebUIを確認できる。なお、アクセス時に認証を要求されるが、confで設定したuserとpasswordを指定すればよい。

http://localhost:9001/

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-27-12-02-08

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-12-20-53-16

上記では、プログラム名「sample」がrunning状態となっており、sampleのリンクやTail -fをクリックすると以下のような出力を確認できる。また、プロセス単体及びプロセスをまとめて起動・停止を行なうことができる。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-12-21-13-57

supervisorctlでsupervisordに接続

続いてsupervisorctlでアクセスしてみる。helpコマンドでコマンドリストが表示される。help <command>でコマンド詳細を確認できる。

ここでは、先ほどのsampleプログラムを停止してみる。stopでプロセス名を指定しないとusageが表示される。続いてプロセス名を正しく指定して、stopコマンドを実行すると停止できる。

WebUIでrunningとなっていたプロセスのステータスもstoppedになっていることを確認できる。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-12-22-13-30

プロセスが異常終了した場合

もしプロセスが何らかの理由でダウンした場合、デフォルトの設定では再度プロセスを開始する。killコマンドでSIGTERMを送ってみる。

続いてSIGSEGVを送ってみる。

予期せぬ異常終了時にもプロセスがリスタートされていることを確認できた。ただ、本来はプロセスが異常終了しないように根本原因を特定し問題を解決する必要があるだろう。

プロセスを開始できなかった(終了する)場合

仮にプロセスが開始できなかった場合、リトライ回数の上限まで起動を試みた後fatal状態になる。

試しにスクリプトをexitstaus 0で終了させてみる。

ログには以下のように出力された。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-11-27-15-33-25

数回リトライした後FATAL状態に移行し、プロセス開始が停止されたことを確認できる。

以上サンプルプログラムをsupervisor経由で実行し、supervisorでプロセス管理するイメージを掴むことができた。運用ではsupervisord自体の監視が必要になるだろう。

supervisordのシグナルハンドリング

supervisordがハンドリングするシグナルには以下のようなものがある。

TERM、INT、QUIT

supervisordとそのすべての子プロセスをshutdownする。以下はSIGTERMを送った例。

シグナルを受信したsupervisordは以下のようなログを出力する。

HUP

すべての子プロセスを停止し設定をリロード、続いてプロセスを開始する。

シグナルを受信したsupervisordは以下のようなログを出力する。

USR2

メインとすべての子プロセスのログを再オープンする。

シグナルを受信したsupervisordは以下のようなログを出力する。

supervisord.conf

supervisord関連の設定はこのconfに記述していくことになる。読み込みの優先順位や主なセクションについてまとめる。詳細は、本家の公式ドキュメントまたはソースのoptions.pyを参照のこと。

設定ファイルの優先順位

設定ファイルは、以下の順で探索される。

  1. <supervisor_bindir>/etc/supervisord.conf
  2. <supervisor_bindir>/supervisord.conf
  3. supervisord.conf
  4. etc/supervisord.conf
  5. /etc/supervisord.conf
  6. /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を指定

status、help、restartとコマンド実行して見た結果、以下の履歴が保存される。

[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は、0203となる。
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にした状態でプロセスからサブプロセスを実行して親プロセスにシグナルを送出してみる。

続いて、supervisord.confを以下のようにする。

supervisordを起動する。

プロセスツリーを確認する。

サププロセスとして実行されていることを確認できる。続いて、supervisorctlからstopコマンドでSIGTERMを送る。

pstreeでgrepしても確認できないので、親・子プロセスとも停止している。

続いて、stopasgroup = falseにして実行して同様な操作をしてみたところ以下のようにリペアレンティングされていることを確認できる。

supervisorctl stopでなく端末からシグナルを送ってみる。最初の状態は以下。

続いてSIGTERMを送る。

親プロセスは変わっていることを確認できる。

参考リンク

詳解UNIXプログラミング 第3版
翔泳社 (2014-06-05)
売り上げランキング: 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

コメント

タイトルとURLをコピーしました