web-dev-qa-db-ja.com

Capistrano3.xでUnicornを起動または再起動する

Capistrano3.0.1でcap production deployを実行すると、Unicornを起動または再起動しようとしています。次のようなものを使用してCapistrano2.xで作業した例がいくつかあります。

namespace :Unicorn do
  desc "Start Unicorn for this application"
  task :start do
    run "cd #{current_path} && bundle exec Unicorn -c /etc/Unicorn/myapp.conf.rb -D"
  end
end

しかし、Capistrano3.xのdeploy.rbrunを使用しようとすると、未定義のメソッドエラーが発生します。

これが私が試したいくつかのことです:

# within the :deploy I created a task that I called after :finished
namespace :deploy do
...

  task :Unicorn do
    run "cd #{current_path} && bundle exec Unicorn -c /etc/Unicorn/myapp.conf.rb -D"
  end

  after :finished, 'deploy:Unicorn'

end

また、:restartタスク内に実行を入れてみました

namespace :deploy do
  desc 'Restart application'
  task :restart do

  on roles(:app), in: :sequence, wait: 5 do
    # Your restart mechanism here, for example:
    # execute :touch, release_path.join('tmp/restart.txt')
    execute :run, "cd #{current_path} && bundle exec Unicorn -c /etc/Unicorn/deployrails.conf.rb -D"
  end
end    

ローカルシェルでrun "cd ... " then I'll get a間違った数の引数(0の場合は1) `を使用した場合。

Ssh'd VM ShellからUnicorn -c /etc/Unicorn/deployrails.conf.rb -Dを使用してUnicornプロセスを開始できます。

KillUSR2を使用してVMシェルからマスターUnicornプロセスを強制終了できますが、プロセスが強制終了されてもエラーが発生します。その後、Unicorn -c ...を使用してプロセスを再開できます。

$ kill USR2 58798
bash: kill: USR2: arguments must be process or job IDs

私はRubyに非常に慣れていません、Railsおよび一般的なデプロイメント。Ubuntu、Nginx、RVM、およびUnicornを使用したVirtualBoxセットアップがあります。これまでのところかなり興奮していますが、これは本当に私をいじって、アドバイスや洞察をいただければ幸いです。

12
kaplan

Capistrano 3(私は2を使用)について具体的なことは何も言えませんが、これは役立つと思います: Capistrano v3のサーバーでシェルコマンドを実行する方法は? 。また、ユニコーン関連の経験を共有することもできます。これがお役に立てば幸いです。

24時間年中無休のグレースフルリスタートアプローチが必要だと思います。

この件については ユニコーンのドキュメント を参照してみましょう。正常な再起動(ダウンタイムなし)には、次の2つの戦略を使用できます。

  1. kill -HUP Unicorn_master_pidアプリで「preload_app」ディレクティブを無効にする必要があり、すべてのUnicornワーカーの開始時間が長くなります。あなたがそれと一緒に暮らすことができるなら-続けてください、それはあなたの呼び出しです。

  2. kill -USR2 Unicorn_master_pidkill -QUIT Unicorn_master_pid

すでにパフォーマンスの問題に対処している場合の、より洗練されたアプローチ。基本的に、Unicornマスタープロセスを再実行します。その後、前のプロセスを強制終了する必要があります。理論的には、usr2-sleep-quitアプローチを扱うことができます。もう1つの(そして正しい方法は)Unicorn before_forkフックを使用することです。これは、新しいマスタープロセスが生成されたときに実行され、新しい子を自分で探します。 config /Unicorn.rbに次のようなものを置くことができます。

# Where to drop a pidfile
pid project_home + '/tmp/pids/Unicorn.pid'

before_fork do |server, worker|
  server.logger.info("worker=#{worker.nr} spawning in #{Dir.pwd}")

  # graceful shutdown.
  old_pid_file = project_home + '/tmp/pids/Unicorn.pid.oldbin'
  if File.exists?(old_pid_file) && server.pid != old_pid_file
    begin
      old_pid = File.read(old_pid_file).to_i
      server.logger.info("sending QUIT to #{old_pid}")
      # we're killing old Unicorn master right there
      Process.kill("QUIT", old_pid)
    rescue Errno::ENOENT, Errno::ESRCH
      # someone else did our job for us
    end
  end
end

新しいユニコーンが労働者をフォークする準備ができたら、古いユニコーンを殺すのは多かれ少なかれ安全です。その方法でダウンタイムが発生することはなく、古いユニコーンはワーカーが終了するのを待ちます。

そしてもう1つ-あなたはそれを runit またはinitの監督下に置くことをお勧めします。そうすれば、capistranoのタスクはsv reload Unicornrestart Unicorn、または/etc/init.d/Unicorn restartのように簡単になります。これは良いことです。

6
dredozubov

私は次のコードを使用しています:

namespace :Unicorn do
  desc 'Stop Unicorn'
  task :stop do
    on roles(:app) do
      if test("[ -f #{fetch(:Unicorn_pid)} ]")
        execute :kill, capture(:cat, fetch(:Unicorn_pid))
      end
    end
  end

  desc 'Start Unicorn'
  task :start do
    on roles(:app) do
      within current_path do
        with Rails_env: fetch(:Rails_env) do
          execute :bundle, "exec Unicorn -c #{fetch(:Unicorn_config)} -D"
        end
      end
    end
  end

  desc 'Reload Unicorn without killing master process'
  task :reload do
    on roles(:app) do
      if test("[ -f #{fetch(:Unicorn_pid)} ]")
        execute :kill, '-s USR2', capture(:cat, fetch(:Unicorn_pid))
      else
        error 'Unicorn process not running'
      end
    end
  end

  desc 'Restart Unicorn'
  task :restart
  before :restart, :stop
  before :restart, :start
end
13
Alexey Poimtsev

これをリングに投げるだけです: capistrano 3 Unicorn gem

ただし、gem(およびinit.dスクリプトを使用しないアプローチ)に関する私の問題は、Unicornプロセスを管理する方法が2つある可能性があることです。 1つはこのキャップタスクを使用し、もう1つはinit.dスクリプトを使用します。 Monit/Godのようなものは混乱し、2つのUnicornプロセスを開始しようとしている理由のデバッグに何時間も費やす可能性があり、その後、人生を憎み始める可能性があります。

現在、capistrano3とUnicornで以下を使用しています。

  namespace :Unicorn do
  desc 'Restart application'
    task :restart do
      on roles(:app) do
        puts "restarting Unicorn..."
        execute "Sudo /etc/init.d/Unicorn_#{fetch(:application)} restart"
        sleep 5
        puts "whats running now, eh unicorn?"
        execute "ps aux | grep Unicorn"
      end
    end
end

上記はpreload_appと組み合わされています:trueと@dredozubovによって言及されたbefore_forkおよびafter_forkステートメント

Init.d/UnicornスクリプトにUnicorn_application_nameという名前を付けたことに注意してください。

開始された新しいワーカーは、古いワーカーを強制終了する必要があります。 ps aux | grep Unicornで、古いマスターが消える前に数秒間ぶらぶらしていることがわかります。

4
Danny

書かれているようにネイティブのカピストラーノの方法を使用してみることができます ここ

Preload_app:trueで、oldbinpidをクリーンアップするためにcapistranoが必要な場合:

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'Unicorn:legacy_restart'
  end
end
0
Dmitriy