Запуск или перезапуск Единорога с Capistrano 3.x

Я пытаюсь запустить или перезапустить Unicorn, когда я делаю cap production deploy с Capistrano 3.0.1. У меня есть несколько примеров, которые я получил, работая с Capistrano 2.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

Но когда я пытаюсь использовать run в deploy.rb для Capistrano 3.x я получаю неопределенную ошибку метода.

Вот несколько вещей, которые я попробовал:

# 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неверное количество аргументов (1 для 0)`в локальной оболочке.

Я могу начать процесс единорога с unicorn -c /etc/unicorn/deployrails.conf.rb -D из моей оболочки ssh'd VM.

Я могу уничтожить основной процесс Unicorn из оболочки виртуальной машины, используя kill USR2, но даже если процесс завершен, я получаю сообщение об ошибке. Затем я могу начать процесс снова, используя unicorn -c ...

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

Я очень новичок в Ruby, Rails и Deployment в целом. У меня есть настройка VirtualBox с Ubuntu, Nginx, RVM и Unicorn, я до сих пор очень взволнован, но этот действительно мне мешает, любой совет или понимание приветствуются.

4 ответа

Решение

Не могу сказать ничего конкретного о Capistrano 3(я использую 2), но я думаю, что это может помочь: Как запускать команды оболочки на сервере в Capistrano v3?, Также я могу поделиться опытом, связанным с единорогом, надеюсь, это поможет.

Я предполагаю, что вы хотите изящный перезапуск 24/7.

Давайте посмотрим документацию единорога по этому вопросу. Для корректного перезапуска (без простоев) вы можете использовать две стратегии:

  1. kill -HUP unicorn_master_pid Это требует, чтобы ваше приложение отключило директиву preload_app, увеличивая время запуска каждого из работников единорога. Если вы можете жить с этим - продолжайте, это ваш звонок.

  2. kill -USR2 unicorn_master_pidkill -QUIT unicorn_master_pid

Более сложный подход, когда вы уже имеете дело с проблемами производительности. По сути, он повторно выполнит мастер-процесс единорога, а затем вы должны убить его предшественника. Теоретически вы можете иметь дело с подходом usr2-sleep-quit. Другой (и, можно сказать, правильный) способ - использовать хук 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

Более или менее безопасно убивать старого единорога, когда новый готов раскошелиться на рабочих. Вы не получите никакого простоя таким образом, и старый единорог будет ждать, пока его рабочие закончат.

И еще одна вещь - вы можете поставить его под контроль runit или init. Таким образом, ваши задачи в Capistrano будут такими же простыми, как sv reload unicorn, restart unicorn или же /etc/init.d/unicorn restart, Это хорошая вещь.

Я использую следующий код:

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

Я просто собираюсь бросить это на ринге: capistrano 3 самоцвет единорога

Однако моя проблема с гемом (и любым подходом, НЕ использующим скрипт init.d), состоит в том, что теперь у вас может быть два метода управления процессом единорога. Один с этой задачей шапки и один со скриптами init.d. Такие вещи, как Monit / God, будут сбиты с толку, и вы можете часами отлаживать, почему у вас есть два процесса единорога, пытающихся запустить, и тогда вы можете начать ненавидеть жизнь.

В настоящее время я использую следующее с capistrano 3 и единорогом:

  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 и операторами before_fork и after_fork, упомянутыми @dredozubov

Примечание. Я назвал свой скрипт init.d/unicorn unicorn_application_name.

Новый запущенный работник должен убить старого. Вы можете увидеть с ps aux | grep unicorn что старый мастер висит на несколько секунд, прежде чем исчезнет.

Чтобы просмотреть все заглавные буквы:

cap -T

и оно показывает:

***
cap unicorn:add_worker             # Add a worker (TTIN)
cap unicorn:duplicate              # Duplicate Unicorn; alias of unicorn:re...
cap unicorn:legacy_restart         # Legacy Restart (USR2 + QUIT); use this...
cap unicorn:reload                 # Reload Unicorn (HUP); use this when pr...
cap unicorn:remove_worker          # Remove a worker (TTOU)
cap unicorn:restart                # Restart Unicorn (USR2); use this when ...
cap unicorn:start                  # Start Unicorn
cap unicorn:stop                   # Stop Unicorn (QUIT)
***

Итак, для запуска единорога в производство:

cap production unicorn:start

и перезапустите:

cap production unicorn:restart 

PS не забываем правильно использовать gem capistrano3-unicorn

https://github.com/tablexi/capistrano3-unicorn

Вы можете попробовать использовать родной способ Capistrano, как написано здесь:

Если preload_app:true и вам нужно capistrano для очистки вашего старого pid:

after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:legacy_restart'
  end
end
Другие вопросы по тегам