これまでスクリプトをデーモン化するために daemontools をよく使っていたのですが、同じコマンドを複数プロセス起動させたいときに煩雑というか、そもそもこのやりかたあってんの? って思ったので、代替になりそうなものをいくつか試しました。
例として、w1.sh
と w2.sh
の 2 つのサービスを、w1.sh
は 2 プロセス、w2.sh
は 3 プロセス起動したいものとします。
daemontools
- http://cr.yp.to/daemontools.html
- 定番
- 下記の SRPM から入れるとインストールが簡単
- 1サービス=1プロセスが基本
- 複数プロセスを起動したければその数だけサービスを定義する必要がある
- もしくはサービスとして起動したプロセスでさらにプロセスマネージャーみたいにするか
# インストール sudo yum -y install rpm-build wget http://mirrors.qmailtoaster.com/daemontools-toaster-0.76-1.3.6.src.rpm rpmbuild --rebuild daemontools-toaster-0.76-1.3.6.src.rpm sudo rpm -ivh ~/rpmbuild/RPMS/x86_64/daemontools-toaster-0.76-1.3.6.x86_64.rpm # systemd のユニットファイル sudo tee /etc/systemd/system/daemontools.service <<EOS [Unit] Description = daemontools After = network.target [Service] ExecStart = /command/svscanboot Restart = always Type = simple [Install] WantedBy = multi-user.target EOS # daemontools を起動 sudo systemctl daemon-reload sudo systemctl start daemontools sudo systemctl status daemontools sudo systemctl enable daemontools # サービスの設定 sudo mkdir /service/.w1-1 sudo mkdir /service/.w1-2 sudo mkdir /service/.w2-1 sudo mkdir /service/.w2-2 sudo mkdir /service/.w2-3 sudo ln -sf /vagrant/w1.sh /service/.w1-1/run sudo ln -sf /vagrant/w1.sh /service/.w1-2/run sudo ln -sf /vagrant/w2.sh /service/.w2-1/run sudo ln -sf /vagrant/w2.sh /service/.w2-2/run sudo ln -sf /vagrant/w2.sh /service/.w2-3/run sudo touch /service/.w1-1/down sudo touch /service/.w1-2/down sudo touch /service/.w2-1/down sudo touch /service/.w2-2/down sudo touch /service/.w2-3/down sudo ln -sf .w1-1 /service/w1-1 sudo ln -sf .w1-2 /service/w1-2 sudo ln -sf .w2-1 /service/w2-1 sudo ln -sf .w2-2 /service/w2-2 sudo ln -sf .w2-3 /service/w2-3 # サービスを開始する sudo svc -u /service/* # サービスの一覧表示 sudo svstat /service/* # サービスの再起動 sudo svc -t /service/* # サービスを停止する sudo svc -d /service/* # サービスを無効にする sudo svc -d /service/* && sudo svc -x /service/* && sudo rm /service/*
supervisor
- http://supervisord.org/
- 定番
- epel から yum でインストールできる
- 設定ファイルの
numprocs
でプロセス数を指定可能
# インストール sudo yum -y install supervisor # supervisor 起動 sudo systemctl start supervisord.service sudo systemctl status supervisord.service sudo systemctl enable supervisord.service # サービスの設定 sudo tee /etc/supervisord.d/app.ini <<EOS [program:w1] command=/vagrant/w1.sh process_name=%(program_name)s-%(process_num)d numprocs=2 autostart=false [program:w2] command=/vagrant/w2.sh process_name=%(program_name)s-%(process_num)d numprocs=3 autostart=false EOS # 反映 sudo supervisorctl update # サービスの開始 sudo supervisorctl start all # サービスの再起動 sudo supervisorctl restart all # サービスの停止 sudo supervisorctl stop all
pm2
- http://pm2.keymetrics.io/
- 基本的には Node.js のアプリ用
- だけど Node.js 以外にも使える
- 設定ファイルの
instances
でプロセス数を指定可能 - モニタとかデプロイ?とか多機能?
- 使わなさそう
- 一般ユーザーで pm2 コマンド実行するとデーモンが立ち上がってしまう
~/.pm2
が pm2 のデータディレクトリになっているため
# インストール sudo yum install nodejs npm sudo npm install -g pm2 # systemd のユニットとして登録 sudo pm2 startup systemd # サービスの設定 cat <<'EOS'> app.json [ { "name" : "w1", "script" : "w1.sh", "exec_mode" : "fork_mode", "instances" : "2" }, { "name" : "w2", "script" : "w2.sh", "exec_mode" : "fork_mode", "instances" : "3" } ] EOS # サービスの登録と開始 sudo pm2 start app.json # サービスの一覧表示 sudo pm2 list # サービスの停止 sudo pm2 stop all # サービスの開始 sudo pm2 start all # サービスの再起動 sudo pm2 restart all # サービスの削除 sudo pm2 delete all
forever
- https://github.com/foreverjs/forever
- 基本的には Node.js のアプリ用
- だけど Node.js 以外にも使える
- 1サービス=1プロセスが基本
- 複数プロセスを起動したければその数だけサービスを定義する必要がある
- もしくはサービスとして起動したプロセスでさらにプロセスマネージャーみたいにするか
# インストール sudo yum install nodejs npm sudo npm install -g forever # サービスの設定 cat <<'EOS' > forever.json [ { "command": "/bin/bash", "script": "w1.sh" }, { "command": "/bin/bash", "script": "w1.sh" }, { "command": "/bin/bash", "script": "w2.sh" }, { "command": "/bin/bash", "script": "w2.sh" }, { "command": "/bin/bash", "script": "w2.sh" } ] EOS # サービスの開始 sudo forever start forever.json # サービスの一覧表示 sudo forever list # サービスの再起動 sudo forever restartall # サービスの停止 sudo forever stopall
foreman
- https://ddollar.github.io/foreman/
- 他の類似ツールの設定ファイルをエクスポートできる
- supervisord とか upstart とか systemd とか
- コマンドラインオプションでプロセス数を指定可能
- respawn はしない
- 複数プロセスのどれかが死ぬと全部死ぬ
# インストール sudo yum -y install ruby rubygems sudo gem install foreman # サービスの設定 cat <<EOS> Procfile w1: ./w1.sh w2: ./w2.sh EOS # サービスの開始(Ctrl+C で終了) foreman start -c -m w1=2,w2=3 # いろいろなサービス管理ツールの設定にエクスポート foreman export -c w1=2,w2=3 supervisord ./supervisord foreman export -c w1=2,w2=3 systemd ./systemd foreman export -c w1=2,w2=3 upstart ./upstart
systemd
- systemd でもテンプレートユニットを使えば同じコマンドを複数プロセス起動できそう
sudo tee /etc/systemd/system/app.target <<EOS [Unit] StopWhenUnneeded = true Wants = \ w1.target \ w2.target [Install] WantedBy = multi-user.target EOS sudo tee /etc/systemd/system/w1.target <<EOS [Unit] StopWhenUnneeded=true PartOf = app.target Wants = \ w1@1.service \ w1@2.service EOS sudo tee /etc/systemd/system/w2.target <<EOS [Unit] StopWhenUnneeded=true PartOf = app.target Wants = \ w2@1.service \ w2@2.service \ w2@3.service EOS sudo tee /etc/systemd/system/w1@.service <<EOS [Unit] Description = w1 After=network.target PartOf = w1.target [Service] ExecStart = /vagrant/w1.sh Restart = always Type = simple [Install] WantedBy = multi-user.target EOS sudo tee /etc/systemd/system/w2@.service <<EOS [Unit] Description = w2 After=network.target PartOf = w2.target [Service] ExecStart = /vagrant/w2.sh Restart = always Type = simple [Install] WantedBy = multi-user.target EOS sudo systemctl daemon-reload # サービスの開始 sudo systemctl start app.target # サービスの一覧 sudo systemctl list-units "w[12]@*" # w1 だけ再起動 sudo systemctl restart w1.target # サービスを停止 sudo systemctl stop app.target
まとめ
- daemontools はたくさん設定するのが辛い
- supervisor は良さそう
- CentOS 6 で 2 系を入れた時は supervisorctl が応答なくなたりしてたきもする
- CentOS 7 で 3 系を入れてみた感じ問題はなさそう
- pm2 と forever は Node.js って感じある
- Node.js 以外でも使えるけどあんまり使われてなさそうな、雰囲気を感じる
- foreman は respawn しないのが辛そう
- systemd が foreman を respawn するにせよ
- 1 プロセス死んだだけで全部が再起動されるのは過剰では?
- そもそも他とくらべてツールの系統が違う
- foreman はシステムに 1 つのサービスマネージャーってわけではない
- 他はシステムに 1 つのサービスマネージャーって感じ
- 次のような複数の foreman を起動する構成を考えるとこれはこれでありかも?
- systemd
- foreman (serviceA) -> serviceA
- foreman (serviceB) -> serviceB
- systemd
- 他のツールだと次のようになって systemd から見ると 1 つのサービスに見える
- systemd
- supervisor
- serviceA
- serviceB
- supervisor
- systemd
- systemd でできるなら systemd でもいいんじゃないか?
- テンプレートユニットや PartOf や Wants を使えばなんとかなりそう
- プロセスの数だけ Wants に羅列する必要があるのは辛いか
ほかのツールみたいなおもしろ機能なないけれども(WebUI とか)、どうせ systemd は居るわけなので、systemd でやるのがよいだろうか。