Supervisorで簡単にデーモン化

  • 362
    いいね
  • 1
    コメント

やりたいこと

常時起動させたいスクリプトなど、デーモンプロセスとして動かしたいことがあると思います。
しかし例えば/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で見えます。
  • 登録したプロセスが異常終了した場合にメールで通知させる。