Edited at

Supervisorで簡単にデーモン化

More than 1 year has passed since last update.


やりたいこと

常時起動させたいスクリプトなど、デーモンプロセスとして動かしたいことがあると思います。

しかし例えば/etc/init.dのスクリプトなどを自分で書くとなると・・・


  • PIDファイルの管理をいちいち書くのが面倒でミスりやすい。

  • ステータスの取得とかも同様。

  • そもそもそんなローレベルのツールを使わなくてもよい。もっとユーザレベルに近いもので充分。

  • 一般ユーザで起動停止くらいさせたい。

つまりは、大体同じ様になるはずの 「プロセス管理スクリプト書くのが面倒」 なのと、

サービスとして登録してしまうと 「基本はrootで起動停止管理」 になるので、

この2つを避けたいということになります。

systemdを使うとスクリプトを書く必要はなくなりますが、


  • rootでなければ起動停止ができない、という扱いにしたくない。

  • stdout/errに色々吐きまくって直したくない。

  • システムのサービス扱いではなくカジュアル起動停止させたい。

といった場合にも需要があるかと思います。


deamonize tool

この手の問題にはdaemon化のツールを使うことになります。

daemontoolsとかforeverとか。

ここではpythonで実装されている「supervisor」を使ってみます。安定性もよいので。


  • 2〜3年ほど3.X系バージョンで運用しましたがsupervisordそのものが落ちたことはありません。


supervisor


  • プロセス管理/デーモン化のツール。

  • コンフィグちょっと書くだけで簡単にデーモンプロセスの生成/管理が可能。

  • 本家のドキュメントはこちら




試しに


インストール

方法は大きく2通り。


  1. EPELリポジトリからインストール

  2. pythonパッケージマネージャ(pip/easy_install)を使う。

1の方法ではバージョンが古いことがあります。

最新バージョンを使いたい場合には2の方法を使います。


  • 特にバージョン2.X系を使うよりは様々な機能が追加された3.X系を使うべきでしょう。

  • 古いバージョンだと例えばstopasgroup(stopの際にchild含むプロセスグループをkillする)が使えなかったりします。


1. EPELからインストールする場合


  • supervisord本体及び、supervisordの管理スクリプトが/etc/init.dに入り、serviceコマンドで管理できます。

yum install supervisor


  • (CentOSではEPELリポジトリはデフォルトでは有効化されていないので、登録してない場合は事前にこちらを。)

rpm --import http://apt.sw.be/RPM-GPG-KEY.dag.txt

rpm -ivh http://apt.sw.be/redhat/el6/en/x86_64/rpmforge/RPMS/rpmforge-release-0.5.3-1.el6.rf.x86_64.rpm


  • CentOS7系でも同じような手順を踏むと思われます。その場合supervisord本体の管理をsystemdで行えるようになるでしょう。


2. pip/easy_installを使う。

pip/easy_installなどのpythonパッケージマネージャからインストールすると、

EPELリポジトリからのインストールとは異なりデフォルトではsupervisord自体のサービス管理は含まれません。

そちらは手動でやっておくと良いでしょう。


  • supervisordのインストール

sudo easy_install supervisor

# または

sudo pip install supervisor

そもそもpythonパッケージマネージャを入れていない場合、

easy_installを使うにはsudo yum install python-setuptoolsを、

pipを使うには、easy_installを入れた後sudo easy_install pipを実行しておきましょう。


  • デフォルトコンフィグファイル生成

EPELリポジトリインストールでは自動的に/etc/supervisord.confに配置されますが、これを手動生成します。

sudo echo_supervisord_conf > /etc/supervisord.conf


  • includeコンフィグ用のディレクトリ作成

EPELリポジトリインストールでは自動的に/etc/supervisord.dが生成されていますので、これを作っておきます。

sudo mkdir /etc/supervisord.d


  • supervisordログファイル

supervisord本体が吐くログファイル周りの調整を行います。

デフォルトのコンフィグでは/tmp/supervisord.logなので、

/etc/supervisord.confを修正し、/var/log/supervisor/supervisord.logにします。

[supervisord]

# ログディレクトリ
;logfile=/tmp/supervisord.log
logfile=/var/log/supervisor/supervisord.log

ログ出力先のディレクトリを作成し、ついでにlog rotationの設定も行っておきます。

sudo mkdir /etc/supervisord.d

sudo sh -c "echo '/var/log/supervisor/*.log {
missingok
weekly
notifempty
nocompress
}' > /etc/logrotate.d/supervisor"


  • pid, includeの設定

こちらも/etc/supervisord.confを修正しておきます。

pidファイルは/var/run/以下に生成するようにし、

/etc/supervisord.d/以下の設定ファイルをincludeできるようにします。

[supervisord]

# ...中略
# pidファイル
;pidfile=/tmp/supervisord.pid
pidfile=/var/run/supervisord.pid

# ...中略

# includeセクションがコメントアウトされているので、コメントインして下記の用に修正。
[include]
files = supervisord.d/*.ini


  • supervisord本体のシステムサービス登録(CentOS6系)

initスクリプトは作成してくれた方がいらっしゃるようで、ありがたく利用させてもらいましょう。

https://github.com/Supervisor/initscripts

何種類かのディストロに対応していますが、今回は下記を使います。

https://github.com/Supervisor/initscripts/blob/master/redhat-init-equeffelec


sudo curl -o /etc/rc.d/init.d/supervisord https://raw.githubusercontent.com/Supervisor/initscripts/master/redhat-init-equeffelec
sudo chmod 755 /etc/rc.d/init.d/supervisord
sudo chkconfig --add supervisord


  • supervisord本体のシステムサービス登録(CentOS7系)

CentOS7ではsystemdに登録することになります。

systemdのunitファイルは下記を参考にして作ります。

https://github.com/zokeber/supervisor-systemd/blob/master/etc/systemd/system/supervisord.service

下記の内容で/etc/systemd/system/supervisord.serviceに格納します。

[Unit]

Description=Supervisor process control system for UNIX
Documentation=http://supervisord.org
After=network.target

[Service]
ExecStart=/usr/bin/supervisord -n -c /etc/supervisord.conf
ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown
ExecReload=/usr/bin/supervisorctl $OPTIONS reload
KillMode=process
Restart=on-failure
RestartSec=50s

[Install]
WantedBy=multi-user.target

作成後は、 systemctl list-unit-files --type=service でsystemdへの管理登録を確認し、試しに起動してみます。

systemctl start supervisord

systemctl status supervisord
systemctl stop supervisord

問題なければ自動起動に登録しておきます。

systemctl enable supervisord.service


supervisordのコンフィグ


  • /etc/supervisord.confを編集して、以下をコメントインします。

[inet_http_server]

port=127.0.0.1:9001

[supervisorctl]
serverurl=unix:///var/tmp/supervisor.sock
serverurl=http://127.0.0.1:9001


  • webの管理コンソールを開放し、同時にroot以外のユーザからのクライアントコマンド許可を行っています。


プロセス管理登録

自分がインストールしたsupervisorはversion 3系で、2系とはコンフィグが若干異なるようです。

特にログ出力の辺りで。(2系は古いので3系使いましょう)

以下、ジョブの標準出力ログ格納ディレクトリを/var/log/supervisor/jobsにしています。そのまま使う場合は予め作成しておきます。また、ローテーションの設定も以下は適当です。


  • GrowthForecast登録の例

[program:GrowthForecast]

command=/usr/local/bin/growthforecast.pl --enable-float-number --data-dir /data/gf ; 起動コマンド
user=monadmin ; 起動ユーザ
autorestart=true ; プロセスダウン時に自動再起動
stdout_logfile=/var/log/supervisor/jobs/GrowthForecast-supervisord.log ; 標準出力ログ
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=5
stdout_capture_maxbytes=1MB
redirect_stderr=true ; エラー出力を標準出力にリダイレクト

これを/etc/supervisord.d/GrowthForecast.iniにでも作成しておきます。


  • HRForecast登録の例。


    • /opt/HRForecastディレクトリにインストールしてあります。



[program:HRForecast]

command=perl hrforecast.pl --config config.pl ; direcotryからの相対パスでOK。
user=monadmin
directory=/opt/HRForecast ; インストールディレクトリがある場合にはこちらに。
autorestart=true
stdout_logfile=/var/log/supervisor/jobs/HRForecast-supervisord.log
stdout_logfile_maxbytes=1MB
stdout_logfile_backups=5
stdout_capture_maxbytes=1MB
redirect_stderr=true

こちらも同じく/etc/supervisord.d/HRForecast.iniにでも作成しておきます。


起動確認

sudo service supervisor start

/var/log/supervisor以下のログをチェックしておくといいでしょう。

今回の設定なら、設定したプロセス(GrowthForecastやHRForecast)のstdout/errも出てきてます。

起動後は、root以外からクライアントコマンドのsupervisorctlを叩いてみます。

単独で叩けば、コマンドラインの管理インタフェースに入れます。

で、成功していれば、以下の様に見えます。

[monadmin@myhost]% supervisorctl

GrowthForecast RUNNING pid 24955, uptime 0:12:00
HRForecast RUNNING pid 24956, uptime 0:12:00
supervisor>

CLIコンソール上からは、start|stop|restart [プロセス名]、

statusで管理プロセスの一覧が出てきます。

CLIコンソールに入らなくても、supervisorctl {start|stop|restart|status} [プロセス名] などが可能です。

rootにならなくてもできるので、

ユーザレベルから管理できるデーモンが出来上がりました。


失敗していると

[monadmin@myhost]% supervisorctl

GrowthForecast FATAL can't find command 'growthforecast.pl'
HRForecast RUNNING pid 8136, uptime 0:00:29
supervisor>

起動失敗時にはステータスがFATALになります。

PATHの通ってないコマンドを書いちゃったのがこれでした。


やってないこと&その他


  • セキュリティ関連を普通は考えます。userやpasswordを設定しましょう。


    • このままだと一般ユーザ全てから出来てしまうので。



  • psコマンドでプロセスツリーを見てみると、rootのsupervisor配下に登録プロセスがぶら下がってるのが解ります。


    • ps auxwwfとかで見てみましょう。



  • webコンソールも持っています。http://127.0.0.1:9001で見えます。

  • 登録したプロセスが異常終了した場合にメールで通知させる。