pumaがdaemonとして動かせなくなったので、systemdで動かすときのpuma.serviceの書き方

最終更新日

アイキャッチ

はじめに

Railsをコンテナ以外のEC2などで実行しているみなさん、capistranoやpuma使っていますか!?

今回はdaemonizeオプションが削除されたpumaをタスクマネージャーであるsystemdで動かすためのtipsです。
Railsを6.1に上げたらpumaのバージョンも当然上がっていて、bash上でpumaを直接バックグランド実行できなくなっており、様々なdocumentを読んでたどり着いたのが今回の設定です。
最適な設定になっているわけではないと思いますが、どなたかの役に立てたら幸いです。

2021.06.18 更新 capistrano3-pumaのコマンド実行時の挙動について追記
2021.07.08 更新 環境変数の注意事項について、コマンド備忘について追記

目次

  1. 概要
  2. バージョン
  3. 手順
    1. Gemの追加
    2. puma.rb, puma.serviceをデプロイ
    3. puma.serviceを編集
    4. 説明
    5. コマンド備忘
  4. さいごに

概要

  • Railsのpumaをbackground実行するdaemonizeオプションが削除されたため、pumaをsystemdで動かす際の備忘録です
    • 詳しくはpuma/systemd.mdを参照ください
    • ちゃんとプロセス管理しろよ!って言われていますね。
  • capistranoでデプロイした時にpumaのプロセスをどう管理するか(restartするか)迷ったので、capistrano前提になっています
  • capistranoの基本的なデプロイができる前提で、pumaのプロセスをsystemdで管理するための設定を記載します
  • コピペして使える設定ファイルの情報ではなく、各プロジェクトにあった設定の書き方がわかるような内容を目指します
    • ※ 設定ファイルも記載してあります

バージョン

  • rails 6.1
  • puma 5.1.1
  • capistrano 3.15.0
  • capistrano-rails 1.6.1
  • capistrano-rbenv 2.2.0
  • capistrano3-puma 5.0.2
  • sd_notify 0.1.0

手順

1. Gemの追加

以下をGemfileに追加

gem 'sd_notify'

group :development do
  gem 'capistrano'
  gem 'capistrano3-puma'
  gem 'capistrano-rails'
  gem 'capistrano-rbenv'
end

※ sd_notifyは状態変更をタスクマネージャー(今回はsystemd)に通知するためのツールです。
様々な言語で実装されています。

2. puma.rb, puma.serviceをデプロイ

※ 2021.06.18 訂正
以下2のコマンドを叩いてもファイルがアップロードされないかもしれません。
ただし、その場合は手でファイルを作ってしまえば良いので、サンプルに従って直接ファイルを作成してください。

  1. puma.rbを$stageへアップロード(${stage}はstagingやproductionなどの環境名)
    bundle exec cap $stage puma:config
  2. puma.serviceを$stageへアップロード
    bundle exec cap $stage puma:systemd:config

puma:configタスクを実行すると"#{shared_dir}/puma.rb"が$stageに作られます。
puma:systemd:configタスクを実行すると$stageに/etc/systemd/system/puma.serviceが作られます。

3. puma.serviceを編集

そして/etc/systemd/system/puma.serviceを編集します。
コメント部分は適宜削除してください

[Unit]
Description=Puma HTTP Server for ${your app name} (production)
After=network.target

[Service]
# puma 5.1以降で使える設定です。これによりsd_notifyからsystemdに通知が送られ、再起動されるようです
# puma 5.1未満はsimpleで利用ください
Type=notify
# 実行ユーザーです。EC2であれば以下で動きますが、別ユーザーを作るのが良さそうです
User=ec2-user
# 正直よくわかりませんでした(capistrano-pumaのデフォルトまま)
WatchdogSec=10
# プロセスの実行ディレクトリです '/var/www’部分もご自身の環境に合わせて適宜変更ください
WorkingDirectory=/var/www/${your app name}/current
# 環境変数
Environment=RAILS_ENV=production
Environment=USING_WEB_SERVER=true
# 環境変数ファイル指定 コレ大事
EnvironmentFile=/var/www/${your app name}/shared/.env

# 下記はrbenv前提でのサンプルです。ご自身の実行環境に合わせてコマンドは適宜変更ください
ExecStart=/home/ec2-user/.rbenv/shims/bundle exec pumactl start -e production
ExecReload=/bin/kill -TSTP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID

Restart=always

[Install]
WantedBy=sockets.target

4. 説明

※ 2021.07.08 追記

# 環境変数ファイル指定 コレ大事
EnvironmentFile=/var/www/${your app name}/shared/.env

こちらの環境変数ファイルの指定が大事です。
これがないと puma.service から.envが読まれなくて環境変数が設定されないものがありました。(設定されたものもあったようなので、Railsの読み込み順序なども関係あるかも?深く検証できていません。)

.env の記述内容は以下のようにローカルなどで使う場合と同じです。

DATABASE_USERNAME=xxxx
DATABASE_PASSWORD=yyyy

5. コマンド備忘

  • プロセス再起動

    sudo systemctl restart puma.service
    sudo systemctl restart sidekiq.service
  • service設定の再読み込み

    sudo systemctl daemon-reload

さいごに

pumaのリポジトリのPR(こちら)でもdaemonizeオプション消すなという反発があって、混乱が見られますね。さらにdaemonizeを復活させたリポジトリが出てきているのも面白いです。

個人的にはsystemdに慣れていなかったので導入には戸惑いましたが、できてしまえばこれまでの管理よりも楽な気がします。

以上参考になったら幸いです。

stmon19

遊びが一番 人生遊び 好きにまみれてます