概要
サーバでは様々なプロセスを実行する必要があるが、これをどう管理するかは悩み所になる。
ここでは強力で柔軟なプロセス管理ツール「Supervisor」に関して記述する。
Supervisorに関して
「Supervisor」は Python で記述された、プロセス管理ツール。
プロセス管理ツールと言うと「upstart」や「daemontools」が利用されていると思われる。
「upstart」は強力ではあるが、柔軟性がまだそれほど無いため、高度なプロセス管理はまだ難しい状況だと思われる。
「daemontools」は ノウハウが蓄積されており、強力で柔軟性が高いツールだが、2001年以降公式では更新されておらず、動作が不安定にってしまう環境も存在している。パッチを当てれば良いが、環境によって動作が変化してしまう場合もあり、安心して利用できない状況になってしまった。
「Supervisor」は積極的に開発され、非常に安定したツールとなっている。
機能的には「daemontools」とほぼ同様の事が可能。
Python で記述されることで、Unix互換システムにおいて、快適に動作する。当然 Mac でも動作する。
現在の Linux サーバは Python はほぼ必須でインストールされている、という状況なので、ツールが Python で記述されていることは利点の一つになりえる。
Supervisorの利点は以下となる。全機能はマニュアル「Supervisor」を参照。
- 積極的に開発されている
- 設定ファイルが比較的簡単
- プロセスのグループ化が容易
- プロセスの状態により処理を実行することが可能
- サブプロセスの管理も可能
- ログを高度に処理できる
- Webインターフェースが存在する
- XMP-RPCインターフェースが存在する
インストール
Supervisorをインストールする場合、通常virtualenvにより環境を構築する。
参考に、以下インストール手順を示した fabfile を配置した。以下のスクリプトはインストールディレクトリは「/opt/python」で、作業ディレクトリは「/opt/supervisor」として記述してある、また、この fabfile はあまり、汎用的には記述していない、あくまで参考である。
実行は「fab install」で実行可能
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from fabric.decorators import task
from fabric.api import (
sudo,
run,
cd,
put,
env,
)
from fabric.contrib.files import exists
@task
def install():
"""
Supervisor
"""
setup_venv()
install_supervisor()
setup_bin()
setup_conf()
setup_upstart()
@task
def setup_venv():
"""
virtualenv による Python 環境構築
"""
with cd(env.path):
run('wget https://raw.github.com/pypa/virtualenv/master/virtualenv.py')
sudo('python virtualenv.py --distribute /opt/python')
@task
def install_supervisor():
"""
Supervisor インストール
"""
run('source /opt/python/bin/activate')
sudo('/opt/python/bin/pip install Supervisor')
@task
def setup_bin():
"""
実行ファイル設定
"""
work_dir = '/opt/supervisor/bin'
if not exists('{0}'.format(work_dir)):
sudo('mkdir -p {0}'.format(work_dir))
put('./fabfile{0}/*'.format(work_dir),
'{0}/'.format(work_dir), use_sudo=True)
sudo('chown root:root {0}/*'.format(work_dir))
sudo('chmod 755 {0}/*'.format(work_dir))
@task
def setup_conf():
"""
設定ファイル
"""
work_dir = '/opt/supervisor'
if not exists('{0}'.format(work_dir)):
sudo('mkdir -p {0}/etc'.format(work_dir))
sudo('mkdir -p {0}/var/log'.format(work_dir))
sudo('mkdir -p {0}/var/run'.format(work_dir))
work_dir = '/opt/supervisor/etc'
conf_file = '{0}/supervisord.conf'.format(work_dir)
if not exists('{0}'.format(work_dir)):
sudo('mkdir -p {0}'.format(work_dir))
put('./fabfile{0}'.format(conf_file),
'{0}'.format(conf_file), use_sudo=True)
work_dir = '/opt/supervisor/etc/supervisor.d'
conf_file = '{0}/*.conf'.format(work_dir)
if not exists('{0}'.format(work_dir)):
sudo('mkdir -p {0}'.format(work_dir))
put('./fabfile{0}'.format(conf_file),
'{0}'.format(conf_file), use_sudo=True)
@task
def setup_upstart():
"""
upstart 設定
"""
conf_file = '/etc/init/supervisor.conf'
put('./fabfile{}'.format(conf_file),
'{0}'.format(conf_file), use_sudo=True)
sudo('chown root:root {0}'.format(conf_file))
管理用スクリプトの配置
Supervisor をインストールすると、インストール場所の「bin」以下に「supervisord」と「supervisorctl」の2ファイルが生成される。
これを直接利用しても良いが、自分は、一つのサーバで複数のSupervisorを起動する要件が発生する場合があるため、以下のようにスクリプトを作成している。
このスクリプトは実行する Python の指定と、設定ファイルの指定をしているだけだが、用途によっては便利だろう。
以下が「supervisord」と同じ機能のファイル
#!/opt/python/bin/python
# -*- coding: utf-8 -*-
import os
import sys
SRC_DIR=os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.argv.extend(['-c', '{0}/etc/supervisord.conf'.format(SRC_DIR)])
import supervisor.supervisord
if __name__ == '__main__':
supervisor.supervisord.main()
以下が「supervisorctl」と同じ機能のファイル。
#!/opt/python/bin/python
# -*- coding: utf-8 -*-
import os
import sys
SRC_DIR=os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
sys.argv[1:1] = ['-c', '{0}/etc/supervisord.conf'.format(SRC_DIR)]
import supervisor.supervisorctl
if __name__ == '__main__':
supervisor.supervisorctl.main(sys.argv[1:])
設定ファイル
設定ファイルの雛形は「echo_supervisord_conf」プログラムによって生成可能。
とりあえず以下のように記述すると最低限の動作はする。「%(here)s」は設定ファイルのあるディレクトリを示す。
「include」の「file」は現在のバージョンではまだ「%(here)s」が使えない。
[supervisord]
childlogdir = %(here)s/../var/log
logfile = %(here)s/../var/log/supervisor.log
logfile_maxbytes = 50MB
logfile_backups = 10
loglevel = info
pidfile = %(here)s/../var/run/supervisor.pid
umask = 022
nodaemon = false
nocleanup = false
[inet_http_server]
port = 127.0.0.1:9001
username =
password =
[supervisorctl]
serverurl = http://127.0.0.1:9001
username =
password =
[rpcinterface:supervisor]
supervisor.rpcinterface_factory=supervisor.rpcinterface:make_main_rpcinterface
[include]
files = /opt/supervisor/etc/supervisor.d/*.conf
upstartの設定
Supervisor自身をSupervisorで管理することはできないので、Supervisorは upstartで管理する。
以下のようなファイルを「/etc/init」以下に「supervisor.conf」として配置する。
description "supervisor"
start on runlevel [2345]
stop on runlevel [!2345]
respawn
chdir /opt/supervisor
exec sudo -i /opt/python/bin/python /opt/supervisor/bin/supervisord -n -d /opt/supervisor
pre-stop exec sudo -i /opt/python/bin/python /opt/supervisor/bin/supervisorctl stop all
プロセス管理設定
これで Supervisor は起動している。「supervisorctl status」を実行するとまだ管理対象が存在しないことがわかる。
とりあえず、nginx の管理を設定してみる。
管理対象のプロセスはフォアグラウンドで起動させる必要がある。nginx の設定を変更する。
daemon off;
Supervisor の設定ファイルで「include」の「files」で指定したディレクトリに以下のようなファイルを「nginx.conf」のような名前で配置する。
[program:nginx]
command=/opt/nginx/sbin/nginx -c /opt/nginx/conf/nginx.conf
redirect_stderr=true
stdout_logfile=%(here)s/../var/log/%(program_name)s_stdout.log
stderr_logfile=%(here)s/../var/log/%(program_name)s_stderr.log
autostart=true
autorestart=true
ここで注意すべきなのは「%(here)s」は、元設定ファイルのカレントディレクトリになるということ。パスには注意する。
以下のようにすることで、有効になる。
# 設定読み込み
supervisorctl reread
# 設定反映
supervisorctl update
# 確認
supervisorctl status
設定を反映するまでは、有効にならない。
以下のように、起動、終了、再起動が可能。
supervisorctl stop nginx
supervisorctl start nginx
supervisorctl restart nginx
「autostart=true」を設定しているので、Supervisor が起動すると自動起動する。
「autorestart=true」を設定しているため、異状終了しても管理対象プロセスは復旧してくる。kill などして、確認してみると良い。
Webインターフェース、XML-RPC
SupervisorはHTTPのWebインターフェエースをもっている。また XML-RPC による管理も可能。
HTTPSを利用したい場合は、nginx などの HTTPサーバを経由させれば良い。
上の設定ファイルを利用している場合はポート9001になる。
その他機能
他の機能はマニュアルを読むのが良い。機能は高機能なので、いろいろできる。