ฉันจะเรียกใช้งานคราดจาก Capistrano ได้อย่างไร


105

ฉันมี deploy.rb ที่สามารถปรับใช้แอปของฉันบนเซิร์ฟเวอร์ที่ใช้งานจริงได้

แอปของฉันมีงานคราดที่กำหนดเอง (ไฟล์. rake ในไดเร็กทอรี lib / งาน)

ฉันต้องการสร้างงานแคปที่จะรันงานคราดนั้นจากระยะไกล


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 rake ดังนั้นการตั้งค่า rvm จะรับคราดที่ถูกต้อง
DGM

8
ด้วย 'Bundle exec' ถ้ามี
Bogdan Gusiev

44

... สองสามปีต่อมา ...

ดูปลั๊กอินรางของ 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

3
สำหรับ capistrano v3 เท่านั้น
phillbaker

ช่วยได้มาก ขอบคุณ! @Mirek Rusin
Nishant Shrivastava

คำตอบอื่น ๆ การใช้งานrunนั้นจะใช้ได้กับ capistrano จนถึงเวอร์ชัน 2 จากเวอร์ชัน 3 นี่คือวิธีที่จะไป
Don Giulio

44

Capistrano 3 Generic Version (รันงานคราดใด ๆ )

การสร้างคำตอบของ Mirek Rusin รุ่นทั่วไป:

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ต้องมาจากอัญมณีรางคาปิสตราโน


1
สิ่งนี้รองรับเฉพาะอาร์กิวเมนต์เดียวหากคุณแทนที่ rake args[:command] ด้วย execute :rake, "#{args.command}[#{args.extras.join(",")}]" คุณสามารถดำเนินการงานที่มีหลายอาร์กิวเมนต์ดังนี้: cap production invoke["task","arg1","arg2"]
Robin Clowers

1
@ โรบิน Clowerscap staging invoke['task[arg1\,arg2]']คุณสามารถส่งผ่านข้อโต้แย้งหลายเช่น ฉันชอบวิธีนี้กับวิธีที่คุณพูดถึงเพราะมันสะท้อนให้เห็นถึงการเรียกคราดจริง cap staging invoke['task1 task2[arg1] task3[arg2\,arg3]']ด้วยวิธีนี้คุณยังสามารถโยงหลายงานซึ่งมักจะมีประโยชน์: ใช้ได้กับคราด 10.2.0 หรือใหม่กว่า
marinosb

นี่ยอดเยี่ยมมาก - ฉันอยากจะทราบว่าคุณต้องรวม: app เป็นหนึ่งในบทบาทเซิร์ฟเวอร์ของคุณ
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คือ gotcha - ตอนแรกฉันไม่ได้คิดถึงมันและคิดไม่ออกว่าทำไมงานถึงไม่ทำอะไรเลย


2
การปรับปรุงเล็กน้อย: หากคุณแทนที่อัฒภาคด้วย && คำสั่งที่สอง (การรันงานคราด) จะไม่ทำงานหากคำสั่งแรก (การเปลี่ยนไดเร็กทอรี) ล้มเหลว
เทฟลอน Ted

2
วิธีนี้จะใช้ไม่ได้หากคุณกำลังปรับใช้กับเซิร์ฟเวอร์หลายเครื่อง มันจะเรียกใช้งานคราดหลายครั้ง
Mark Redding

4
เราควรเคารพการตั้งค่าคราดของ"cd #{deploy_to}/current && #{rake} <task_name> RAILS_ENV=production"
คาปิสตราโน

@Mark Redding: คุณสามารถกำหนดหนึ่งในเซิร์ฟเวอร์ในบทบาทของตัวเองสำหรับงานคราดและ จำกัด งาน capistrano ของคุณให้ทำงานบนเซิร์ฟเวอร์ที่มีบทบาทนั้นได้หรือไม่?
mj1531

ฉันทำอะไรบางอย่างที่ฉันสร้างงานใน deploy.rb ของฉัน งานนั้นมี a: role =>: db ซึ่งจะดำเนินการบนเซิร์ฟเวอร์เดียวกับที่ฉันกำหนดให้เป็นหลักสำหรับ db: migrate
Mark Redding

20

ใช้การเรียกคราดแบบ Capistrano

มีวิธีทั่วไปที่ "ใช้ได้" กับrequire 'bundler/capistrano'ส่วนขยายอื่น ๆ ที่ปรับเปลี่ยนคราด สิ่งนี้จะใช้ได้กับสภาพแวดล้อมก่อนการผลิตหากคุณใช้หลายขั้นตอน สาระสำคัญ? ใช้ config vars ถ้าคุณทำได้

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
นี่เป็นทางออกที่ดีที่สุดโดยใช้ค่าคาปิสตราโนที่มีอยู่
ซ้ำ

2
อาจคุ้มค่าที่จะเพิ่มว่าถ้างานของคุณเป็นเนมสเปซ (กล่าวคือไม่ได้กำหนดไว้ในเนมสเปซระดับบนสุด) คุณอาจต้องใช้top.runแทนrun
dolzenko

ขอบคุณ @dolzenko พบเพียงเอกสารสำหรับtopวิธีการ ในกรณีที่เรากำหนดไว้runในเนมสเปซเดียวกันtop.runจำเป็นต้องมีมิฉะนั้นก็ยังควรค้นหาระดับบนสุดrunแม้ว่างานจะเป็นเนมสเปซก็ตาม ฉันพลาดอะไรไปหรือเปล่า? เกิดอะไรขึ้นในกรณีของคุณ?
Captainpete

1
เห็นได้ชัดว่าฉันไม่ได้กำหนดวิธีการรันไว้ในเนมสเปซเดียวกันดังนั้นไม่แน่ใจว่าทำไมฉันถึงต้องการสิ่งนั้น ไม่ว่าในกรณีใด Capistrano 2.0 จะเป็นประวัติศาสตร์และเวอร์ชันถัดไปเป็นแบบ Rake (ทำให้คาดเดาได้ง่ายขึ้น)
dolzenko

16

ใช้capistrano-rakeอัญมณี

เพียงแค่ติดตั้งอัญมณีโดยไม่ต้องยุ่งกับสูตรอาหารคาปิสตราโนที่กำหนดเองและดำเนินงานคราดที่ต้องการบนเซิร์ฟเวอร์ระยะไกลเช่นนี้:

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

ที่อนุญาตให้เรียกใช้งานคราดคล้ายกับการใช้วิธีการรัน (คำสั่ง)


หมายเหตุ: คล้ายกับสิ่งที่Dukeเสนอ แต่ฉัน:

  • ใช้ latest_release แทน current_release - จากประสบการณ์ของฉันมันเป็นมากกว่าสิ่งที่คุณคาดหวังเมื่อเรียกใช้คำสั่งคราด
  • ปฏิบัติตามหลักการตั้งชื่อของ Rake และ Capistrano (แทน: cmd -> task and rake -> run_rake)
  • อย่าตั้งค่า RAILS_ENV = # {rail_env} เนื่องจากตำแหน่งที่เหมาะสมในการตั้งค่าคือตัวแปร default_run_options เช่น default_run_options [: env] = {'RAILS_ENV' => 'production'} # -> DRY!

5

มีเสื้อคลุมอัญมณีที่น่าสนใจที่ทำให้งานคราดของคุณพร้อมใช้งานเป็นงาน 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ช่วยให้คุณสามารถกำหนดวิธีที่คุณต้องการเรียกใช้งานคราดในเครื่องและจากระยะไกล (ไม่มีอีกแล้ว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

นี่คือสิ่งที่ฉันใส่ใน deploy.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 กำหนดตัวแปรคราดของตัวเอง (ใช้เพื่อกำหนดว่าจะใช้คราดใด) และทำให้ใบเสร็จรับเงินในตัวแตกต่างกันเช่นรายการที่รวบรวมสินทรัพย์ล่วงหน้า
Michael

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
{deploy_to} / current ใช้ไม่ได้ที่นี่ ลิงก์สัญลักษณ์ไม่มีการเปลี่ยนแปลง หากคุณอัปเดตงานคราดสิ่งนี้จะเรียกใช้รหัสเก่า ลองใช้ {release_path} แทน
Mark Redding

ข้อมูลเพิ่มเติมคือสแปม?
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

ดังนั้นฉันจึงได้ดำเนินการนี้ ตะเข็บทำงานได้ดี อย่างไรก็ตามคุณต้องมีตัวจัดรูปแบบเพื่อใช้ประโยชน์จากโค้ดจริงๆ

หากคุณไม่ต้องการใช้ฟอร์แมตเตอร์เพียงแค่ตั้งค่าระดับการบันทึกเป็นโหมดดีบัก semas เหล่านี้ถึง 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

นี่คือฟอร์แมตเตอร์ที่ฉันสร้างขึ้นเพื่อใช้กับโค้ดด้านบน มันขึ้นอยู่กับ: 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

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

บางทีมันอาจจะมีประโยชน์สำหรับใครบางคน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.