やりたいこと
常時起動させたいスクリプトなど、デーモンプロセスとして動かしたいことがあると思います。
しかし例えば/etc/init.dのスクリプトなどを自分で書くとなると・・・
- PIDファイルの管理をいちいち書くのが面倒でミスりやすい。
- ステータスの取得とかも同様。
- そもそもそんなローレベルのツールを使わなくてもよい。もっとユーザレベルに近いもので充分。
- 一般ユーザで起動停止くらいさせたい。
つまりは、大体同じ様になるはずの 「プロセス管理スクリプト書くのが面倒」 なのと、
サービスとして登録してしまうと 「基本はrootで起動停止管理」 になるので、
この2つを避けたいということになります。
systemdを使うとスクリプトを書く必要はなくなりますが、
- rootでなければ起動停止ができない、という扱いにしたくない。
- stdout/errに色々吐きまくって直したくない。
- システムのサービス扱いではなくカジュアル起動停止させたい。
といった場合にも需要があるかと思います。
deamonize tool
この手の問題にはdaemon化のツールを使うことになります。
daemontoolsとかforeverとか。
ここではpythonで実装されている「supervisor」を使ってみます。安定性もよいので。
- 2〜3年ほど3.X系バージョンで運用しましたがsupervisordそのものが落ちたことはありません。
supervisor
- プロセス管理/デーモン化のツール。
- コンフィグちょっと書くだけで簡単にデーモンプロセスの生成/管理が可能。
- 本家のドキュメントはこちら
試しに
- 私はメトリクスのグラフ化にGrowthForecastとHRForecastを使用させてもらってますので、試しにこれらをデーモン化してみます。
- GrowthForecast http://kazeburo.github.io/GrowthForecast/
- HRForecast http://blog.nomadscafe.jp/2013/02/hrforecast--.html
- この時メインで試したOSはCentOS6.4です。
インストール
方法は大きく2通り。
- EPELリポジトリからインストール
- 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
何種類かのディストロに対応していますが、今回は下記を使います。
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ファイルは下記を参考にして作ります。
下記の内容で/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で見えます。
- 登録したプロセスが異常終了した場合にメールで通知させる。
- 下記の通りやってみました。
- Supervisorのプロセス異常終了をメールで通知