Как запустить рейк из Capistrano?

У меня уже есть deploy.rb, с помощью которого можно развернуть мое приложение на моем производственном сервере.

Мое приложение содержит настраиваемую задачу rake (файл .rake в каталоге lib / tasks).

Я хотел бы создать задачу ограничения, которая будет удаленно запускать эту задачу рейка.

Может ли кто-нибудь объяснить плюсы / минусы использования собственной переменной #{rake} capistrano? Кажется, это не всегда лучший вариант.

lulalala 07.11.2012 07:13
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
107
1
63 612
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Ответ принят как подходящий
run("cd #{deploy_to}/current && /usr/bin/env rake `<task_name>` RAILS_ENV=production")

Нашел с гуглом - http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

С RAILS_ENV=production была ошибка - я сначала не подумал об этом и не мог понять, почему задача ничего не делает.

Небольшое улучшение: если вы замените точку с запятой на &&, то второй оператор (запускающий задачу rake) не будет запущен, если первый оператор (изменение каталога) завершится неудачно.

Teflon Ted 12.05.2009 19:17

Это не сработает, если вы выполняете развертывание на нескольких серверах. Он будет запускать задачу rake несколько раз.

Mark Redding 04.06.2011 00:36

нужно действительно уважать настройку граблей Capistrano "cd #{deploy_to}/current && #{rake} <task_name> RAILS_ENV=production"

kares 14.06.2011 15:13

@Mark Redding: Не могли бы вы назначить одному из серверов отдельную роль для задач rake и ограничить выполнение задачи capistrano только на серверах с этой ролью?

mj1531 24.06.2011 19:25

Я сделал что-то, где создал задачу в своем deploy.rb. У этой задачи есть: role =>: db, поэтому она будет выполняться только на том же сервере, который я определил как основной для db: migrate.

Mark Redding 27.11.2011 00:38

Немного более явным образом в вашем \config\deploy.rb добавьте вне любой задачи или пространства имен:

namespace :rake do  
  desc "Run a task on a remote server."  
  # run like: cap staging rake:invoke task=a_certain_task  
  task :invoke do  
    run("cd #{deploy_to}/current; /usr/bin/env rake #{ENV['task']} RAILS_ENV=#{rails_env}")  
  end  
end

Затем из /rails_root/ можно запустить:

cap staging rake:invoke task=rebuild_table_abc

лучше использовать / usr / bin / env rake, чтобы настройки rvm подбирали правильный рейк.

DGM 04.11.2010 23:30

С 'bundle exec', если доступно

Bogdan Gusiev 18.03.2011 17:20

Это тоже работает:

run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {'RAILS_ENV' => rails_env})

Подробнее: Capistrano Run

{deploy_to} / current здесь не работает. Символьная ссылка не изменилась. Если вы обновите задачу rake, будет запущен старый код. Вместо этого рассмотрите возможность использования {release_path}.

Mark Redding 04.06.2011 00:35

чем больше инфо спам?

hcarreras 08.07.2014 19:06

Вот что я вложил в свой deploy.rb, чтобы упростить выполнение задач rake. Это простая оболочка метода run () capistrano.

def rake(cmd, options = {}, &block)
  command = "cd #{current_release} && /usr/bin/env bundle exec rake #{cmd} RAILS_ENV=#{rails_env}"
  run(command, options, &block)
end

Затем я просто запускаю любую задачу с граблями, например:

rake 'app:compile:jammit'

это конфликтует, поскольку capistrano определяет свою собственную переменную рейка (используется для определения того, какой рейк использовать) и, таким образом, нарушает встроенные квитанции, например, тот, который предварительно компилирует активы

Michael 17.10.2012 15:57

Я лично использую в производстве такой вспомогательный метод:

def run_rake(task, options = {}, &block)
  command = "cd #{latest_release} && /usr/bin/env bundle exec rake #{task}"
  run(command, options, &block)
end

Это позволяет запускать задачу rake аналогично использованию метода run (command).


ПРИМЕЧАНИЕ: Это похоже на то, что предлагает Герцог, но я:

  • используйте latest_release вместо current_release - по моему опыту это больше, чем вы ожидаете при запуске команды rake;
  • следуйте соглашению об именах Rake и Capistrano (вместо: cmd -> task и rake -> run_rake)
  • не устанавливайте RAILS_ENV = # {rails_env}, потому что правильное место для его установки - это переменная default_run_options. Например, default_run_options [: env] = {'RAILS_ENV' => 'production'} # -> DRY!

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

После установки драгоценного камня просто добавьте его в свой файл config/deploy.rb.

# config/deploy.rb
require 'cape'
Cape do
  # Create Capistrano recipes for all Rake tasks.
  mirror_rake_tasks
end

Теперь вы можете запускать все задачи rake локально или удаленно через cap.

В качестве дополнительного бонуса cape позволяет вам установить, как вы хотите запускать задачу rake локально и удаленно (больше не bundle exec rake), просто добавьте это в свой файл config/deploy.rb:

# Configure Cape to execute Rake via Bundler, both locally and remotely.
Cape.local_rake_executable  = '/usr/bin/env bundle exec rake'
Cape.remote_rake_executable = '/usr/bin/env bundle exec rake'

Примечание: работает только для Capistrano v2.x. Не совместим с Capistrano v3.

nayiaw 09.10.2015 06:42

Используйте призывы граблей в стиле Капистрано

Есть обычный способ «просто работать» с require 'bundler/capistrano' и другими расширениями, изменяющими рейк. Это также будет работать с предпроизводственной средой, если вы используете многоступенчатую версию. Суть? По возможности используйте переменные конфигурации.

desc "Run the super-awesome rake task"
task :super_awesome do
  rake = fetch(:rake, 'rake')
  rails_env = fetch(:rails_env, 'production')

  run "cd '#{current_path}' && #{rake} super_awesome RAILS_ENV=#{rails_env}"
end

Это лучшее решение, где доступны значения капистрано.

loopj 15.07.2012 03:28

Вероятно, стоит добавить, что если ваша задача находится в пространстве имен (т.е. определена не в пространстве имен верхнего уровня), вам, возможно, придется использовать top.run вместо просто run.

dolzenko 02.10.2013 18:02

Спасибо @dolzenko. Только что нашел документы для метода top. В случае, когда мы определили run в том же пространстве имен, требуется top.run, в противном случае он все равно должен найти run верхнего уровня, даже если задача находится в пространстве имен. Я что-то упустил? Что случилось в вашем случае?

captainpete 03.10.2013 05:34

У меня явно не было метода запуска, определенного в том же пространстве имен, поэтому я не уверен, зачем мне это нужно. В любом случае Capistrano 2.0 - это история, а следующая версия основана на Rake (надеюсь, что делает вещи более предсказуемыми).

dolzenko 30.10.2013 12:42
namespace :rake_task do
  task :invoke do
    if ENV['COMMAND'].to_s.strip == ''
      puts "USAGE: cap rake_task:invoke COMMAND='db:migrate'" 
    else
      run "cd #{current_path} && RAILS_ENV=production rake #{ENV['COMMAND']}"
    end
  end                           
end 

Хорошо. Изменение его с RAILS_ENV=production на RAILS_ENV=#{rails_env} позволяет ему работать и на моем промежуточном сервере.

evanrmurphy 21.03.2013 01:33

Большая часть из выше ответ с небольшими улучшениями для запуска любой задачи по рейку из capistrano.

Запустите любую задачу по граблям от capistrano

$ cap rake -s rake_task=$rake_task

# Capfile     
task :rake do
  rake = fetch(:rake, 'rake')
  rails_env = fetch(:rails_env, 'production')

  run "cd '#{current_path}' && #{rake} #{rake_task} RAILS_ENV=#{rails_env}"
end

... пару лет спустя ...

Взгляните на плагин rails capistrano, вы можете увидеть на https://github.com/capistrano/rails/blob/master/lib/capistrano/tasks/migrations.rake#L5-L14, он может выглядеть примерно так:

desc 'Runs rake db:migrate if migrations are set'
task :migrate => [:set_rails_env] do
  on primary fetch(:migration_role) do
    within release_path do
      with rails_env: fetch(:rails_env) do
        execute :rake, "db:migrate"
      end
    end
  end
end

Только для capistrano v3.

phillbaker 21.01.2014 17:01

Очень помогли. Спасибо! @Mirek Rusin

Nishant Shrivastava 14.07.2015 15:29

другие ответы, что использовать run, будет работать на capistrano до версии 2. начиная с версии 3 это путь.

Don Giulio 20.10.2015 15:18

Capistrano 3 Общая версия (запускать любую задачу с граблями)

Создание общей версии ответа Мирека Русина:

desc 'Invoke a rake command on the remote server'
task :invoke, [:command] => 'deploy:set_rails_env' do |task, args|
  on primary(:app) do
    within current_path do
      with :rails_env => fetch(:rails_env) do
        rake args[:command]
      end
    end
  end
end

Пример использования: cap staging "invoke[db:migrate]"

Обратите внимание, что для deploy:set_rails_env требуется драгоценный камень capistrano-rails.

Это поддерживает только один аргумент, если вы замените rake args[:command] на execute :rake, "#{args.command}[#{args.extras.join(",")}]", вы можете выполнить задачу с несколькими аргументами, например: cap production invoke["task","arg1","arg2"]

Robin Clowers 24.09.2014 05:19

@ Робин Клоуэрс Вы можете передать несколько аргументов, например cap staging invoke['task[arg1\,arg2]']. Я предпочитаю этот подход тому, который вы упомянули, потому что он отражает фактический вызов rake. При таком подходе вы также можете объединить несколько задач в цепочку, что часто бывает полезно: cap staging invoke['task1 task2[arg1] task3[arg2\,arg3]']. Работает на рейке 10.2.0 и новее

marinosb 15.10.2014 22:41

это здорово - я хотел бы отметить, что вам нужно включить: app в качестве одной из ролей сервера.

lfender6445 01.11.2015 01:01

Очевидно, это должно было быть "invoke [db: migrate]" ... Исправление сделано.

Abram 23.12.2015 09:18

@Abram с командой, которую вы предложили, я получаю "Не знаю, как создать задачу" invoke "

dc10 25.12.2015 14:09

Вы имеете в виду цитаты? Так что у вас работает только без кавычек @ dc10

Abram 25.12.2015 17:41

@Abram у меня это вообще не работает, как эта шапка production "invoke [load_data]", сама задача объявляется внутри пространства имен deploy

dc10 25.12.2015 17:49

Попался. Что ж, ознакомьтесь с приведенным ниже ответом, который сработал для меня.

Abram 26.12.2015 04:04

Обратите внимание, что current_path не будет работать при первом запуске, поскольку он еще не был создан - используйте release_path вместо этого, если вы планируете включить эту задачу с граблями в свой первый запуск.

Paul Odeon 10.10.2019 13:32

Если вы хотите передать несколько аргументов, попробуйте это (на основе ответа мариносберна):

task :invoke, [:command] => 'deploy:set_rails_env' do |task, args|
  on primary(:app) do
    within current_path do
      with :rails_env => fetch(:rails_env) do
        execute :rake, "#{args.command}[#{args.extras.join(",")}]"
      end
    end
  end
end

Тогда вы можете запустить такую ​​задачу: cap production invoke["task","arg1","arg2"]

Итак, я работал над этим. швы работают хорошо. Однако вам нужен форматировщик, чтобы действительно воспользоваться преимуществами кода.

Если вы не хотите использовать форматировщик, просто установите уровень журнала в режим отладки. Эти семас к ч

SSHKit.config.output_verbosity = Logger::DEBUG

Шапка

namespace :invoke do
  desc 'Run a bash task on a remote server. cap environment invoke:bash[\'ls -la\'] '
  task :bash, :execute do |_task, args|
    on roles(:app), in: :sequence do
      SSHKit.config.format = :supersimple
      execute args[:execute]
    end
  end

  desc 'Run a rake task on a remote server. cap environment invoke:rake[\'db:migrate\'] '
  task :rake, :task do |_task, args|
    on primary :app do
      within current_path do
        with rails_env: fetch(:rails_env) do
          SSHKit.config.format = :supersimple
          rake args[:task]
        end
      end
    end
  end
end

Это средство форматирования, которое я построил для работы с приведенным выше кодом. Он основан на :textimple, встроенном в sshkit, но это неплохой способ вызывать пользовательские задачи. О, это не работает с последней версией sshkit gem. Я знаю, что он работает с 1.7.1. Я говорю это, потому что основная ветвь изменила доступные методы SSHKit :: Command.

module SSHKit
  module Formatter
    class SuperSimple < SSHKit::Formatter::Abstract
      def write(obj)
        case obj
        when SSHKit::Command    then write_command(obj)
        when SSHKit::LogMessage then write_log_message(obj)
        end
      end
      alias :<< :write

      private

      def write_command(command)
        unless command.started? && SSHKit.config.output_verbosity == Logger::DEBUG
          original_output << "Running #{String(command)} #{command.host.user ? "as #{command.host.user}@" : "on "}#{command.host}\n"
          if SSHKit.config.output_verbosity == Logger::DEBUG
            original_output << "Command: #{command.to_command}" + "\n"
          end
        end

        unless command.stdout.empty?
          command.stdout.lines.each do |line|
            original_output << line
            original_output << "\n" unless line[-1] == "\n"
          end
        end

        unless command.stderr.empty?
          command.stderr.lines.each do |line|
            original_output << line
            original_output << "\n" unless line[-1] == "\n"
          end
        end

      end

      def write_log_message(log_message)
        original_output << log_message.to_s + "\n"
      end
    end
  end
end

Это сработало для меня:

task :invoke, :command do |task, args|
  on roles(:app) do
    within current_path do
      with rails_env: fetch(:rails_env) do
        execute :rake, args[:command]
      end
    end
  end
end

Затем просто запустите cap production "invoke[task_name]"

Используйте драгоценный камень capistrano-rake

Просто установите драгоценный камень, не вмешиваясь в пользовательские рецепты капистрано, и выполните желаемые задачи по рейку на удаленных серверах, например:

cap production invoke:rake TASK=my:rake_task

Полное раскрытие: я написал это

Предыдущие ответы мне не помогли, и я нашел следующее: От http://kenglish.co/run-rake-tasks-on-the-server-with-capistrano-3-and-rbenv/

namespace :deploy do
  # ....
  # @example
  #   bundle exec cap uat deploy:invoke task=users:update_defaults
  desc 'Invoke rake task on the server'
  task :invoke do
    fail 'no task provided' unless ENV['task']

    on roles(:app) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :rake, ENV['task']
        end
      end
    end
  end

end

для запуска вашей задачи используйте

bundle exec cap uat deploy:invoke task=users:update_defaults

Может кому будет полезно

Другие вопросы по теме