Як запустити граблі з Capistrano?


105

У мене вже є implemen.rb, який може розгортати додаток на моєму виробничому сервері.

У моєму додатку міститься спеціальна задача граблі (файл .rake в каталозі lib / task).

Я хотів би створити завдання з обмеженням, яке віддалено виконуватиме цю граблі.


2
Чи може хтось пояснити плюси / мінуси використання власної #{rake}змінної capistrano ? Здається, це не завжди найкращий варіант.
lulalala

Відповіді:


59

Трохи більш чітко у вашому \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

1
краще використовувати / usr / bin / env рейку, щоб настройки rvm підбирали правильну рейку.
DGM

8
З 'bundle exec' за наявності
Богдан Гусієв

44

... через пару років ...

Погляньте на плагін Capistrano's rails, ви можете побачити на 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

3
Це лише для capistrano v3.
філбекер

Допомагав багато. Дякую! @Mirek Rusin
Nishant Shrivastava

інші відповіді, що використання runбуде працювати на capistrano до версії 2. З версії 3, це шлях.
Дон Джуліо

44

Загальна версія 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


1
Це підтримує лише один аргумент, якщо ви заміните rake args[:command] на нього, execute :rake, "#{args.command}[#{args.extras.join(",")}]" ви можете виконати завдання з кількома аргументами на кшталт цього: cap production invoke["task","arg1","arg2"]
Робін Клоуерс

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

це чудово - я хочу зазначити, що вам потрібно включити: додаток як одну з ваших ролей сервера.
lfender6445

Мабуть, це потрібно було "викликати [db: migrate]" ... Виправлення зроблено.
Аврам

@Abram з командою, яку ти запропонував, я отримаю "Не знаю, як створити завдання", викликати "
dc10,

41
run("cd #{deploy_to}/current && /usr/bin/env rake `<task_name>` RAILS_ENV=production")

Знайдено в Google - http://ananelson.com/said/on/2007/12/30/remote-rake-tasks-with-capistrano/

Це RAILS_ENV=productionбуло придурком - я не думав про це спочатку і не міг зрозуміти, чому завдання нічого не робить.


2
Невелике поліпшення: якщо ви заміните крапку з комою на &&, то другий оператор (виконує завдання рейку) не запуститься, якщо перше твердження (зміна каталогу) не вдасться.
Тефлоновий Тед

2
Це не спрацює, якщо ви розгортаєтесь на декілька серверів. Він виконує завдання граблі кілька разів.
Марк Реддінг

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

@Mark Redding: Чи можете ви поставити один із серверів у власну роль для виконання завдань і обмежити завдання capistrano виконувати лише на серверах з такою роллю?
mj1531

Я щось зробив там, де створив завдання в моєму розміщенні.rb. Це завдання має: role =>: db на ньому таким чином, що воно буде виконуватися лише на тому самому сервері, який я визначив як моє основне для db: migrate.
Марк Реддінг

20

Використовуйте виклики граблів у стилі Capistrano

Існує загальний спосіб, який буде "просто працювати" з 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

2
Це найприємніше рішення, використовує значення capistrano, де це можливо
loopj

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

Дякую @dolzenko Щойно знайшли документи для topметоду . У випадку, коли ми визначилися runв одному просторі імен, top.runпотрібно, інакше він все-таки повинен знайти верхній рівень runнавіть там, де завдання розміщено на просторі імен. Я щось пропустив? Що сталося у вашому випадку?
капітанпейт

1
У мене явно не було визначено жодного методу запуску в одному просторі імен, тож не знаю, навіщо мені це потрібно. У будь-якому випадку Capistrano 2.0 - це історія, і наступна версія заснована на Rake (що сподівається, що все можна зробити передбачуванішим)
dolzenko

16

Використовуйте capistrano-rakeсамоцвіт

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

cap production invoke:rake TASK=my:rake_task

Повне розкриття: я написав це


7

Я особисто використовую у виробництві такий помічний метод:

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

Це дозволяє виконувати завдання граблі, подібне до використання методу run (command).


ПРИМІТКА. Це схоже на те, що запропонував герцог , але я:

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

5

Є цікава накидка для дорогоцінних каменів, яка робить ваші завдання граблі доступними як завдання Capistrano, тому ви можете виконувати їх віддалено. capeдобре задокументований, але ось короткий огляд того, як налаштувати i.

Встановивши дорогоцінний камінь, просто додайте це у свій config/deploy.rbфайл.

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

Тепер ви можете виконувати всі свої rakeзавдання локально або віддалено cap.

Як додатковий бонус, capeви можете встановити, як ви хочете виконувати завдання граблі локально та віддалено (не більше 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

3
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 

1
Добре. Якщо змінити його, RAILS_ENV=productionщоб RAILS_ENV=#{rails_env}він міг працювати і на моєму сервісі постановки.
evanrmurphy

2

Ось, що я помістив у свою мою voz.rb для спрощення запуску рейкових завдань. Це проста обгортка навколо методу 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 визначає власну змінну рейку (використовується для визначення, яку рейку використовувати), і, таким чином, розбиває вбудовані прийоми, наприклад, ту, яка попередньо компілює активи
Майкл

2

Це працювало для мене:

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]"


1

Більшість з них - це відповідь зверху з незначним вдосконаленням для виконання будь-якого завдання граблі з 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

1

Це також працює:

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

Більше інформації: Capistrano Run


1
{implemen_to} / current тут не працює. Символічне посилання не змінилося. Якщо ви оновите завдання граблі, це запустить старий код. Спробуйте скористатися {release_path} замість цього.
Марк Реддінг

чим більше інформація - це спам?
hcarreras

1

Якщо ви хочете передати кілька аргументів, спробуйте це (на основі відповіді marinosbern):

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"]


0

Тож я над цим працював. це добре працює. Однак вам потрібен форматер, щоб реально скористатися кодом.

Якщо ви не хочете використовувати формат, просто встановіть рівень журналу в режим налагодження. Ці семи до h

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

Це формат, який я створив для роботи з кодом вище. Він заснований на: текстовому простому вбудованому в 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

0

Попередні відповіді не допомогли мені, і я виявив це: З 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

Можливо, комусь це стане в нагоді

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.