【Linux】Supervisor でプロセス制御(Rails + Puma / Capistrano)
EC2(AmazonLinux2)に構築した Railsアプリケーションのプロセス管理、具体的にはデーモンプロセスとして動かすために、今回 Supervisor を使ったので、備忘録として残しておく。
- Supervisor v4.2.1
Supervisor とは
Supervisor とは、Python 製のプロセスの制御・管理ツールで、常時起動させたいスクリプトなどを簡単にデーモン化することができる。(デーモン化することで、クラッシュした際の再起動などを自動で行ってくれる。)
今回は、Rails + Puma で運用しているWEBアプリケーションの Puma のプロセスの制御を Supervisor で行えるようにした。
しかしながら、Linux であれば、「systemd」に service
として登録することで同様の設定を簡単に行うことができる。ただし、systemd の場合、基本は root ユーザーで起動停止管理を行う必要がある。
今回、systemd ではなく、Supervisor を採用した大きな理由としては、Capistrano を使って、一般ユーザーでも起動・停止のプロセス管理を実施したかったことが挙げられる。
Supervisor のコマンド
Supervisor に関して、使用するコマンドは2種類ある。(プロセス管理を行うには、supervisord
が事前に立ち上がっておく必要がある。)
- supervisord:supervisordの起動に使う
- supervisorctl:プロセスの管理・制御で使う
supervisord
supervisord の起動を行う
$ /usr/bin/supervisord -n -c /etc/supervisord.conf
オプションは複数あるが、上記ができていればいいのではないかと思う。
- -c:設定ファイルを指定する
- -n:フォアグラウンドで起動する(こちらを設定することで、
ctrl + c
で停止が可能となる。試験時には、便利。)
詳細は、公式ドキュメント 参照。
supervisorctl
プロセス全体の管理・制御を行う場合
# プロセス全体の起動 $ supervisorctl start all # プロセス全体のステータス確認 $ supervisorctl status # プロセス全体の停止 $ supervisorctl stop all # プロセス全体の再起動 $ supervisorctl restart all # 構成ファイルを再読み込みする(設定変更時、実施要) $ supervisorctl reread # supervisordを再起動する $ supervisorctl reload
1つのプロセスの管理・制御を行う場合
# 起動 $ supervisorctl start <name> # ステータス確認 $ supervisorctl status <name> # 停止 $ supervisorctl stop <name> # 再起動 $ supervisorctl restart <name>
詳細は、公式ドキュメント 参照。
EC2への設定方法
今回は、Puma のプロセスの制御を行う。
1. Supervisorインストール
python パッケージマネージャ(pip/easy_install)を使う。
$ sudo easy_install supervisor $ supervisord -v 4.2.1
2. デフォルトの設定ファイルを生成する
$ echo_supervisord_conf > /etc/supervisord.conf
3. アプリケーション用の設定ファイルを追加する
$ sudo mkdir /etc/supervisord.d
$ sudo vim /etc/supervisord.d/sample-app.conf
# プロセス名を設定する。今回は、sample-appとする。 [program:sample-app] # 実行ディレクトリを指定する(RailsのCapistranoのcurrentディレクトリ) directory=/app/sample-app/current # 実行コマンド(puma起動) command=/bin/bash -c "/opt/rbenv/shims/bundle exec pumactl start" environment=RAILS_ENV="production" autostart=true autorestart=true startsecs=3 user=ec2-user redirect_stderr=false # logファイルの保存先を指定する stderr_logfile=/app/sample-app/shared/log/sample-app.stderr.log stdout_logfile=/app/sample-app/shared/log/sample-app.stdout.log
詳細な設定項目は、公式ドキュメント を参照。
4. 設定ファイルを変更する
変更内容は、以下。
- アプリケーション用の設定ファイルを include できるようにする
- web の管理コンソールを開放し、同時に root 以外のユーザーからのクライアントコマンド許可を行う(Capistranoで実行できるようにしておく)
$ sudo vim /etc/supervisord.conf
# 以下の3箇所のコメントアウトを外してあげる [inet_http_server] port=127.0.0.1:9001 [supervisorctl] serverurl=http://127.0.0.1:9001 [include] files = /etc/supervisord.d/*.conf
# rootユーザー以外の場合に、以下のエラーが出た error: <class 'socket.error'>, [Errno 13] Permission denied: file: /usr/lib64/python2.7/socket.py line: 228
5. supervisord をデーモン化するために、systemd にサービスを登録する
Supervisor を使用するには supervisord をあらかじめ起動しておく必要があるため、systemd にサービスを登録して、supervisord をデーモン化しておく。
$ sudo vim /lib/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
以下のコマンドを実行して、「supervisord.service」が systemd に登録されているか確認する。
systemctl list-unit-files --type=service
無事に、サービス登録がされていたら、以下のコマンドを実行して起動・ステータス確認・停止ができるかを確認する。
# 起動 sudo systemctl start supervisord # 状態確認 sudo systemctl status supervisord ● supervisord.service - Supervisor process control system for UNIX Loaded: loaded (/etc/systemd/system/supervisord.service; disabled; vendor preset: disabled) Active: active (running) since 2020-12-01 00:00:00 UTC # 停止 sudo systemctl stop supervisord
6. 起動している状態で、サービスの自動起動の設定を行う
$ sudo systemctl enable supervisord.service
Created symlink from /etc/systemd/system/multi-user.target.wants/supervisord.service to /usr/lib/systemd/system/supervisord.service.
7. 最後に、supervisor でプロセス制御を行う
# 起動 $ supervisorctl start sample-app # ステータス確認 $ supervisorctl status sample-app # 停止 $ supervisorctl stop sample-app # 再起動 $ supervisorctl restart sample-app # 設定ファイルを変更した場合には、再読み込みが必要 $ supervisorctl reload
無事に、Supervisor で Puma のプロセスを制御できれば設定は完了である。
きちんとデーモン化されているかを確認するために、以下を実行してみる。
# プロセスIDを確認する $ supervisorctl status sample-app sample-app RUNNING pid 26041, uptime 1:00:00 # プロセスを kill する $ kill -9 26041 # 再度、プロセスIDを確認する # プロセスIDが変わっていれば、デーモン化されていることが確認できたことになる $ supervisorctl status sample-app sample-app RUNNING pid 26045, uptime 1:00:00
これで、設定は完了である。
Capistrano の設定
Capistrano から supervisor を操作する場合は、以下の設定をしておく。
namespace :console do desc 'status service' task :status do on roles(:app) do |_host| execute 'supervisorctl status sample-app' end end desc 'start service' task :start do on roles(:app) do |_host| execute 'supervisorctl start sample-app' end end desc 'restart service' task :restart do on roles(:app) do |_host| execute 'supervisorctl restart sample-app' end end desc 'stop service' task :stop do on roles(:app) do |_host| execute 'supervisorctl stop sample-app' end end end
namespace を console
としているので、以下のようにして実行することができる。
# サービス再起動 bundle exec cap {stage} console:restart # サービス確認 bundle exec cap {stage} console:status
まとめ
無事に Supervisor でプロセス制御を行うことができた。簡単に設定できて、非常に使いやすいのではないかと思えた。
それでは、ステキな開発ライフを。