Запуск или перезапуск Единорога с 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.
Давайте посмотрим документацию единорога по этому вопросу. Для корректного перезапуска (без простоев) вы можете использовать две стратегии:
kill -HUP unicorn_master_pid
Это требует, чтобы ваше приложение отключило директиву preload_app, увеличивая время запуска каждого из работников единорога. Если вы можете жить с этим - продолжайте, это ваш звонок.kill -USR2 unicorn_master_pid
kill -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
Вы можете попробовать использовать родной способ Capistrano, как написано здесь:
Если preload_app:true и вам нужно capistrano для очистки вашего старого pid:
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
task :restart do
invoke 'unicorn:legacy_restart'
end
end