Help us understand the problem. What is going on with this article?

Supervisorで簡単にデーモン化

More than 3 years have 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で見えます。
  • 登録したプロセスが異常終了した場合にメールで通知させる。
yushin
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away