序章

Puma は、Rackアプリ(Railsなど)を非常にうまく処理する効率的なRubyWebサーバーです。 Pumaは、スレッドおよび/またはワーカーを使用して同時実行を提供します。 Pumaのクラスターモード(ワーカーを使用)を使用して、ダウンタイムなしでアプリをデプロイできます。 プーマは労働者を一人ずつ再開し、他の労働者はこの間も処理を続けます。 これは、アプリに更新をデプロイするときに、応答の遅延やエラーページがユーザーに表示されなくなるため便利です。

このガイドでは、以下を使用します。

  • PumaをWebサーバーとして
  • Foreman がアプリを管理します(これは厳密には必要ありませんが、生活が少し楽になります)
  • デプロイするCapistrano(デプロイ手順はかなり一般的であり、他の方法に簡単に再適用できます)

このガイドは、使用する既存のRailsアプリがあることを前提としています。 まだそこまで来ていない場合は、Rails入門ガイドを参照してください。 このガイドでは、Ubuntuを使用していることも前提としています。 設定方法については、こちらをご覧ください。 このガイドでは、Upstartを使用します。

Pumaのインストール

PumaはRubyGemsからインストールできます。

gem install puma

インストールすると、次の電話をかけるだけでPumaを使用してアプリを起動できます。

puma config.ru # or whatever your *.ru file is called

ただし、代わりに、Foremanを使用してアプリを管理します。 読む。

フォアマンのインストール

Foremanは、RubyGemsを使用してインストールできます。

gem install foreman

PumaとForemanを使用したレールの構成

まず、Gemfileにプーマとフォアマンを追加します。

# Gemfile
gem 'puma'
gem 'foreman'

そしてインストール:

bundle install

Foremanには、実行するプロセスを指定するために使用されるProcfileが必要です。 プロセスにwebworkerなどの名前を付けることができます。これらの名前を使用して、実行するプロセスのタイプを区別できます。 次に行うことは、Procfileを作成することです。

echo "web: bundle exec puma -e $RAILS_ENV -p 5000 -S ~/puma -C config/puma.rb" >> Procfile

ポート番号は好きなように変更できます。5000を使用します。 次に、puma構成ファイルを作成し、次のように編集します。

# config/puma.rb
threads 1, 6
workers 2

on_worker_boot do
  require "active_record"
  cwd = File.dirname(__FILE__)+"/.."
  ActiveRecord::Base.connection.disconnect! rescue ActiveRecord::ConnectionNotEstablished
  ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"] || YAML.load_file("#{cwd}/config/database.yml")[ENV["RAILS_ENV"]])
end

スレッドとワーカーの数を正しく構成することが重要です。PumaREADMEは、これを行うための最善の方法に関するアドバイスを提供します。 Pumaをクラスターモードで実行するには、少なくとも2人のワーカーが必要です。 通常、VPSで使用可能なコアの数と一致させる必要があります。 Ubuntuでは、次のコマンドを使用できます。

grep -c processor /proc/cpuinfo

コアの数を確認します。 または、使用している液滴の種類に基づいて判断することもできます。 また、各ワーカーは指定された数のスレッドを使用するため、上記の構成では、最小で2つ、最大で12のスレッドが存在することに注意してください。

on_worker_bootブロックは、ワーカーが起動されるたびにActiveRecord接続を確立します(つまり、 デプロイ中)。 別のORMを使用している場合は、ここで適切な接続を行う必要があります。

Procfilepuma.rbを構成すると、アプリケーションを実行できるようになります。 これを行うには、次のコマンドを実行するだけです。

foreman start

ロードされると、アプリはlocalhost:5000(またはProcfileで指定したポート)で利用できるようになります。

展開

Foremanは、他のプロセス管理フォーマットにエクスポートできます。 UbuntuプロセスマネージャーであるUpstartを使用します。 Foremanを使用して、次のコマンドを実行することにより、Ubstart互換のスクリプトをエクスポートできます。

sudo foreman export upstart /etc/init -a puma-test-app -u puma-test-user -l /var/puma-test-app/log

この例では、puma-test-apppuma-test-userは、適切なアプリ名とシステムユーザーに置き換えられます。 ただし、これをローカルで実行する必要はありません。デプロイの一部としてupstartスクリプトを自動的に作成することで、アプリを常に正しく起動し、Upstartで実行を継続できるようにします。

Capistranoを使用してデプロイします。 まだ行っていない場合は、次のコマンドを実行して、Capistranoで動作するようにアプリを設定します。

capify .

アプリのルートディレクトリにあります。 次に、config/deploy.rbで作成したファイルに、以下を追加します。

# config/deploy.rb
set :app_name, "puma-test-app"
set :user, "puma-test-user"

namespace :foreman do
  desc "Export the Procfile to Ubuntu's upstart scripts"
  task :export, :roles => :app do
    run "cd #{current_path} && #{sudo} foreman export upstart /etc/init -a #{app_name} -u #{user} -l /var/#{app_name}/log"
  end
  
  desc "Start the application services"
  task :start, :roles => :app do
    run "#{sudo} service #{app_name} start"
  end
 
  desc "Stop the application services"
  task :stop, :roles => :app do
    run "#{sudo} service #{app_name} stop"
  end
 
  desc "Restart the application services"
  task :restart, :roles => :app do
    run "#{sudo} service #{app_name} start || #{sudo} service #{app_name} restart"
  end
end

foreman:exportタスクはUbuntuのUpstartスクリプトを更新します。これは、デプロイするたびに呼び出されます。 他のタスクは、Upstartがサポートするサービスを管理します。 Procfileは定期的に変更されませんが、変更された場合は、アプリケーションサービスを再起動して、これらの変更を登録する必要があります。 これを実行するには、次を実行します。

cap foreman:restart

ただし、ほとんどの場合、私たちがやりたいのは、段階的な再起動を行うようにPumaに指示することだけです。 これを行うには、Capistrano deploy:restartタスクを使用します。このタスクは、標準のCapistranoデプロイメントの一部として自動的に実行されます。 config/deploy.rbに以下を追加します。

namespace :deploy do
  task :restart, :roles => :app do
    foreman.export

    # on OS X the equivalent pid-finding command is `ps | grep '/puma' | head -n 1 | awk {'print $1'}`
    run "(kill -s SIGUSR1 $(ps -C ruby -F | grep '/puma' | awk {'print $2'})) || #{sudo} service #{app_name} restart"

    # foreman.restart # uncomment this (and comment line above) if we need to read changes to the procfile
  end
end

deploy:restartタスクが最初に行うことは、foreman:exportを呼び出してUpstartスクリプトを更新することです。 次に、SIGUSR1シグナルを実行中のすべてのPumaインスタンスに送信します。 これは、PumaマスタープロセスのプロセスIDを見つけて、適切なシグナルを送信することによって行われます。 コメントアウトされたコマンドはOSXでPIDを検出します。ローカルでテストする必要がある場合に備えて、両方を手元に置いておくと便利な場合があります。 PumaがSIGUSR1信号を受信すると、段階的な再起動を開始します。 なんらかの理由でSIGUSR1信号を送信できない場合は、従来の方法でサービスを再開することにフォールバックします。

Procfileへの変更を登録する必要がある場合は、foreman:restartタスクを呼び出す必要があります。 これには、runで始まる行をコメントアウトし、foreman.restart行のコメントを解除します。 理想的にはProcfileは展開間で同じままであるため、これを定期的に行う必要はありません。

テスト

テストする前に、上記の手順を使用してForemanがUbuntuVPSにインストールされていることを確認してください。

まだ行っていない場合は、Capistranoで動作するようにVPSを設定する必要があります。 まず、Webサーバーやリポジトリなどのconfig.deploy.rbに空欄を埋めます。 次に、以下を実行してVPSを構成します。

cap deploy:setup

その後、次を実行できます。

cap deploy

最初の展開を行います。 このデプロイ中に、アプリはVPS上のUbuntuサービスとして開始されます。 以降のすべての展開では、PumaにSIGUSR1信号が送信され、段階的な再起動がトリガーされます。 再起動プロセス全体を通してアプリを使い続けることができるはずです。

データベースの移行

Pumaが段階的な再起動を実行している間、アプリは2つの異なるコードベースを実行します。 したがって、両方のコードベースが既存のデータベーススキーマで機能することを確認する必要があります。これは、移行を行う必要がある場合は注意が必要な場合があります。 (大幅な移行が必要で、サイトをオフラインにする必要がある場合は、新しいforeman:stop Capistranoタスクを呼び出してから、foreman:startタスクを呼び出して後でオンラインに戻すことができます。 )。