🌊

Rails6 + CapistranoでのPumaのSystemdのデプロイ設定

2021/08/05に公開

株式会社TECH LUCKという会社で代表兼エンジニアをしている齊藤です。

DXプロジェクト、開発プロジェクト、Rails開発などでお困りごとがありましたら弊社HPからご相談をいただけますと幸いです。
以下のような問題に対応することが可能です。

  • プロジェクトでRailsエンジニアが足りなくて困っている
  • Railsのバージョンアップをしたいがノウハウ・リソースが足りなくて困っている
  • オフショア開発をしているが、要件の齟齬やコード品質が悪いので改善したい

また、Railsエンジニアも募集しておりますので、興味がありましたら弊社HPからご連絡いただけますと幸いです。

前提

PumaをSystemdで起動させる際に、Capistranoでのデプロイでの設定になります。

環境

サーバー : AWS EC2
サーバーOS : Amazon Linux
Ruby : v2.7.3
Ruby on Rails : v6.1.4
Capistrano : v3.16.0

環境ごとにpuma.rbの作成

Railsアプリケーションのconfigpumaディレクトリを作成し、環境名のファイルを作成します。

cd config
mkdir puma
touch production.rb

環境ごとにPumaの設定ファイルを作成することにより、環境ごとにPumaの起動の設定を行うことができます。

詳細は以下の記事に書いてあるのでご参考まで。
https://nishinatoshiharu.com/rails-puma-start-patterns/

Pumaではデフォルトの設定ファイルであるconfig/puma.rbのほか、実行環境に応じた、config/puma/環境名.rbという設定ファイルを用意できます。
rails sの場合はconfig/puma/[環境名].rb → config/puma.rbの優先順位で設定ファイルを読み込みます。

config/puma/production.rbに以下の記述をします。

config/puma/production.rb
# bind "unix://#{Rails.root.join('tmp/sockets/puma.sock')}"だとpumactlコマンドで読み込まないため絶対パスで指定
root_dir = '/var/www/アプリケーション名/current'

max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5)
min_threads_count = ENV.fetch('RAILS_MIN_THREADS', max_threads_count)
threads min_threads_count, max_threads_count

worker_timeout 60

bind "unix://#{root_dir}/tmp/sockets/puma.sock"

environment 'production'

pidfile File.expand_path('tmp/pids/server.pid')

stdout_redirect File.expand_path('log/puma_access.log'), File.expand_path('log/puma_error.log'), true

# workerの数は適宜変更する。指定しない場合はsingle modeとなるが、指定した場合はcluster modeとなる。
workers 2

plugin :tmp_restart

systemdの登録

元々Pumaはdaemonizeオプションがあり、そのオプションを使うことでバックグラウンドで起動するようにデーモン化することができました。
しかし、そのdaemonizeオプションで起動がうまくいかなくなるバグがあるため、オプションが削除されたようです。
代わりに、LinuxのSystemdなどでPumaの起動やデーモン化を行うようにするようになったとのことです。

こちらの記事に詳細が記載されていますのでご参考までに。
https://zenn.dev/ymasutani/articles/ce42131f0e7b1a

本番サーバー(Capistranoでアプリがデプロイされるサーバー)にログインし、/etc/systemd/systemの配下にpuma.serviceというファイル名で以下を記述します。

/etc/systemd/system/puma.service
[Unit]
Description=Puma HTTP Server
After=network.target

[Service]
Type=simple
User=ユーザー名
WorkingDirectory=/var/www/アプリケーション名/current
Environment=RAILS_ENV=production
Environment=USING_WEB_SERVER=true
ExecStart=/bin/bash -lc 'bundle exec puma -C config/puma/production.rb'
Restart=always

[Install]
WantedBy=sockets.target

ファイルを作成したら、systemctlに登録するためのコマンドを実行します。

sudo systemctl enable puma.service

Capistranoの設定

Gemの追加とインストール

Gemfileに必要なgemを追加します。

Gemfile
gem 'puma' #元々あると思うが念の為

group :development do
  gem 'capistrano3-puma',    require: false
end
bundle install
bundle exec cap install

Capfileの編集

Capfileに以下の記述を追加します。

Capfile
# 追加する
require 'capistrano/puma'
...
...
...
# 追加する
install_plugin Capistrano::Puma
install_plugin Capistrano::Puma::Systemd

deploy.rbの編集

config/deploy.rb に以下を追記します。
これにより、Capistranoのデプロイの際に、先ほど設定したsystemdでPumaを起動・再起動を行うようになります。

config/deploy.rb
# 以下の記述を追加
set :puma_service_unit_name, 'puma.service'

デプロイ

以上の設定でCapistranoでPumaのデプロイを行うことができるようになります。

bundle exec cap production deploy

Rails7.1の場合の対処法

Rails7.1を利用していると、Railsのバージョンとの兼ね合いでpumaのバージョンを6.0以上にしないと、エラーが出るようになっていたのでpumaのバージョンをあげる。

Gemfile
gem 'puma', '~> 6.0'

また、capistrano3-pumaも普通にgemをインストールすると、pumaのバージョン6との相性が悪く、デプロイの際にエラーが発生するためバージョンを指定する。

Gemfile
gem 'capistrano3-puma', '6.0.0.beta.1', require: false

また、deploy.rbの中でpuma_system_ctl_user:systemに指定しないと、以下のような形でpumaのリスタートが実行され、デプロイの際のpumaの起動の際にエラーが発生してしまう。

# :systemを指定していないと実行されるコマンド
/bin/systemctl --user restart puma.service

これを回避するため、以下をdeploy.rbの中で指定する。

config/deploy.rb
set :puma_systemctl_user, :system

また、Rails7.1からデフォルトで強制的にSSLがオンになっており、強制リダイレクトが発生して画面が見れないエラーが発生することもある。

environments/production.rbの中で以下の指定を行いSSLの強制リダイレクトをOFFにする。

environments/production.rb
`config.force_ssl = false`

Discussion