У меня уже есть deploy.rb, с помощью которого можно развернуть мое приложение на моем производственном сервере.
Мое приложение содержит настраиваемую задачу rake (файл .rake в каталоге lib / tasks).
Я хотел бы создать задачу ограничения, которая будет удаленно запускать эту задачу рейка.

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) не будет запущен, если первый оператор (изменение каталога) завершится неудачно.
Это не сработает, если вы выполняете развертывание на нескольких серверах. Он будет запускать задачу rake несколько раз.
нужно действительно уважать настройку граблей Capistrano "cd #{deploy_to}/current && #{rake} <task_name> RAILS_ENV=production"
@Mark Redding: Не могли бы вы назначить одному из серверов отдельную роль для задач rake и ограничить выполнение задачи capistrano только на серверах с этой ролью?
Я сделал что-то, где создал задачу в своем deploy.rb. У этой задачи есть: role =>: db, поэтому она будет выполняться только на том же сервере, который я определил как основной для db: migrate.
Немного более явным образом в вашем \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 подбирали правильный рейк.
С 'bundle exec', если доступно
Это тоже работает:
run("cd #{release_path}/current && /usr/bin/rake <rake_task_name>", :env => {'RAILS_ENV' => rails_env})
Подробнее: Capistrano Run
{deploy_to} / current здесь не работает. Символьная ссылка не изменилась. Если вы обновите задачу rake, будет запущен старый код. Вместо этого рассмотрите возможность использования {release_path}.
чем больше инфо спам?
Вот что я вложил в свой 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 определяет свою собственную переменную рейка (используется для определения того, какой рейк использовать) и, таким образом, нарушает встроенные квитанции, например, тот, который предварительно компилирует активы
Я лично использую в производстве такой вспомогательный метод:
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).
ПРИМЕЧАНИЕ: Это похоже на то, что предлагает Герцог, но я:
Есть интересная жемчужина мыс, которая делает ваши задачи с граблями доступными как задачи 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.
Есть обычный способ «просто работать» с 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
Это лучшее решение, где доступны значения капистрано.
Вероятно, стоит добавить, что если ваша задача находится в пространстве имен (т.е. определена не в пространстве имен верхнего уровня), вам, возможно, придется использовать top.run вместо просто run.
Спасибо @dolzenko. Только что нашел документы для метода top. В случае, когда мы определили run в том же пространстве имен, требуется top.run, в противном случае он все равно должен найти run верхнего уровня, даже если задача находится в пространстве имен. Я что-то упустил? Что случилось в вашем случае?
У меня явно не было метода запуска, определенного в том же пространстве имен, поэтому я не уверен, зачем мне это нужно. В любом случае Capistrano 2.0 - это история, а следующая версия основана на Rake (надеюсь, что делает вещи более предсказуемыми).
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} позволяет ему работать и на моем промежуточном сервере.
Большая часть из выше ответ с небольшими улучшениями для запуска любой задачи по рейку из 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.
Очень помогли. Спасибо! @Mirek Rusin
другие ответы, что использовать run, будет работать на capistrano до версии 2. начиная с версии 3 это путь.
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"]
@ Робин Клоуэрс Вы можете передать несколько аргументов, например cap staging invoke['task[arg1\,arg2]']. Я предпочитаю этот подход тому, который вы упомянули, потому что он отражает фактический вызов rake. При таком подходе вы также можете объединить несколько задач в цепочку, что часто бывает полезно: cap staging invoke['task1 task2[arg1] task3[arg2\,arg3]']. Работает на рейке 10.2.0 и новее
это здорово - я хотел бы отметить, что вам нужно включить: app в качестве одной из ролей сервера.
Очевидно, это должно было быть "invoke [db: migrate]" ... Исправление сделано.
@Abram с командой, которую вы предложили, я получаю "Не знаю, как создать задачу" invoke "
Вы имеете в виду цитаты? Так что у вас работает только без кавычек @ dc10
@Abram у меня это вообще не работает, как эта шапка production "invoke [load_data]", сама задача объявляется внутри пространства имен deploy
Попался. Что ж, ознакомьтесь с приведенным ниже ответом, который сработал для меня.
Обратите внимание, что current_path не будет работать при первом запуске, поскольку он еще не был создан - используйте release_path вместо этого, если вы планируете включить эту задачу с граблями в свой первый запуск.
Если вы хотите передать несколько аргументов, попробуйте это (на основе ответа мариносберна):
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]"
Предыдущие ответы мне не помогли, и я нашел следующее: От 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
Может кому будет полезно
Может ли кто-нибудь объяснить плюсы / минусы использования собственной переменной
#{rake}capistrano? Кажется, это не всегда лучший вариант.