とーますメモ

Ruby on Rails / Goなどの学習メモ

【Rails5】Systemdを使用したPumaの自動起動設定

自分用メモ。

Systemctlは、Systemdを管理するためのコマンド。
Systemdは、デーモンプロセスを自動立ち上げるるために使用される。
以下のサイトが詳しい。
Systemd メモ書き
いまだにsysvinitの手癖が抜けない人のためのsystemd
Linux女子部 systemd徹底入門

前提

Capistrano3を使用し、デプロイしていることが前提。
公式を見ると、Systemd用の設定が載っていたので
以下のページを参考に設定する。
puma/systemd.md at master · puma/puma · GitHub

公式には、「Type=simple」での設定例、「Type=forking」での設定例が存在するが
「Type=forking」の場合は、サービスが落ちたときなど自動で再起動する機能が使用できないため、
ここでは「Type=simple」での設定を行うこととする。

but is not performing continuous restarts. Therefore running Puma in cluster mode, where the master can restart workers, is highly recommended.

by puma/systemd.md at master · puma/puma · GitHub

またこの設定を使用する場合、Capistranoで「capistrano/puma」を読み込んでいて、且つ「set :puma_daemonize, ture」を設定している場合は必ず「set :puma_daemonize, false」もしくは、設定自体を削除すること!

[参考]
Puma silently exits after "Daemonizing..." from systemd script · Issue #941 · puma/puma · GitHub


deploy.rb

# before
set :puma_daemonize, true
# after
set :puma_daemonize, false

これを設定していると、puma.serviceが動作せず、後述するjournalctlのログには「No Pid 'xxxxx' found」というエラーが表示される。

puma.serviceの作成

「/etc/systemd/system/」内に「puma.service」というファイルを作成

$ cd /etc/systemd/system/
$ vim puma.service

puma.serviceには以下の内容を設定。
{{ working_directory }}はcapistranoの「xxx/current」を指定
{{ shared_directory }}はcapistranoの「xxx/shared」を指定

またsystemdは.barshrcや.bash_profileを読み込まないので
ExecStartには「/bin/bash -lc」でログインシェルを読み込む、.bashrcを読み込む設定にした。
[SOLVED] Where to put environment vars regarding SystemD / System Administration / Arch Linux Forums

[Unit]
Description=Puma Application Server
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory={{ working_directory }}
ExecStart=/bin/bash -lc "/root/.rbenv/bin/rbenv exec bundle exec puma -C {{ shared_directory }}/puma.rb"
ExecStop=/root/.rbenv/bin/rbenv exec bundle exec pumactl -S {{ shared_directory }}/tmp/pids/puma.state stop
TimeoutSec=300
Restart=always

[Install]
WantedBy=multi-user.target

Restartをalwaysにすることで、サービスの再起動を行う。例えばサーバリスタート時や、何らかの理由でpumaが異常終了したとしても自動的に起動する。
※stopで止めた場合は、再起動しない。
WantedBy=multi-user.targetはランレベル3で動作することを意味する。

※forkingを使用する場合は、以下のようにPIDFileを設定する必要がある。

PIDFile={{ shared_directory }}/tmp/pids/puma.pid

systemctlコマンド

# puma.serviceを新規作成後または変更後はこのコマンドを叩かないと反映されない。
systemctl daemon-reload

# 有効化
systemctl enable puma.service

# 起動
systemctl start puma.service

# 停止
systemctl stop puma.service

# ステータス確認
systemctl status puma.service

# 再起動
systemctl restart puma.service

Journalctlコマンド

Systemdのログは、Journalctlコマンドを利用することで確認できる。

journalctl

  • u (Unit): 指定ユニットに関係するログのみ表示
  • b: 直前のサーバ起動以降のログを表示
  • f: tail -f のように、順次表示する
    • no-pager: less コマンドを使用しない
  • a : 長いメッセージを省略しない
    • since='YYYY-MM-DD hh:mm:ss': 指定日以降のログ表示
    • until='YYYY-MM-DD hh:mm:ss': 指定日までのログ表示

by
Systemd メモ書き

自分の場合は、よく以下を使用する。

pumaのログだけを、リアルタイムで確認

$ journalctl -f -u puma

その他所感

capistrano/pumaを読み込んだ状態で、Capistranoを利用しデプロイすると
以下のコマンドが流れる。

$HOME/.rbenv/bin/rbenv exec bundle exec puma -C /var/www/recipe_post/shared/puma.rb --daemon

見ての通り、「--daemon」がついているため、デーモン化されて動作する。
これを変更したりすることは現時点では無理そう。
なぜならpuma.rakeに固定して記述されているため。

以下ページのソースを参照。
capistrano-puma/puma.rake at master · seuros/capistrano-puma · GitHub


[その他参考]
Pumaをsystemdで起動するメモ
Manage Puma with systemd on Ubuntu 16.04 and rbenv · GitHub
「Systemd」を理解する ーシステム管理編ー | ギークを目指して
Systemd入門(4) - serviceタイプUnitの設定ファイル - めもめも
CentOS7系と6系のコマンドの違いについて