Read more

How to use the Capistrano 2 shell to execute commands on servers

Arne Hartherz
August 05, 2013Software engineer at makandra GmbH

Capistrano 2 brings the shell command which allows you to run commands on your deployment targets.
There is also invoke to run a command directly from your terminal.

Illustration money motivation

Opscomplete powered by makandra brand

Save money by migrating from AWS to our fully managed hosting in Germany.

  • Trusted by over 100 customers
  • Ready to use with Ruby, Node.js, PHP
  • Proactive management by operations experts
Read more Show archive.org snapshot

Both commands allow running Capistrano tasks or shell commands, and scope to individual machines or machine roles.

Unfortunately Capistrano 3 does not include these commands any more.

cap shell

Basics

First of all, spawn a Capistrano shell (we're using the multistage extension here):

$ cap staging shell

In your "cap" shell you can now run Capistrano tasks by prepending an exclamation mark. For example:

cap> !deploy:revision
 ** [out :: web1.example.com] 9aeed9030db6a7b5b4ba077337545677b4fd5c22
 ** [out :: web2.example.com] 9aeed9030db6a7b5b4ba077337545677b4fd5c22
 ** [out :: queue.example.com] 9aeed9030db6a7b5b4ba077337545677b4fd5c22

(deploy:revision is a custom task to check the deployed revision)

To run shell commands on each machine, simply put them there as if you were on a regular terminal session:

cap> uname -o
 ** [out :: web1.example.com] GNU/Linux
 ** [out :: web2.example.com] GNU/Linux
 ** [out :: queue.example.com] GNU/Linux

Running more than one shell command

Be aware that shell commands will be sent once, and that your shell on the remote machine is not persistent:

cap> cd /tmp
cap> pwd
 ** [out :: web1.example.com] /home/deploy
 ** [out :: web2.example.com] /home/deploy
 ** [out :: queue.example.com] /home/deploy

Instead, queue them:

cap> cd /tmp && pwd
 ** [out :: web1.example.com] /tmp
 ** [out :: web2.example.com] /tmp
 ** [out :: queue.example.com] /tmp

Running commands only on individual machines

You may have some commands that you want to run only on a subset of machines, e.g. machines running queue workers.

To pick machines by name, use the on keyword:

cap> on web1.example.com uname -o
 ** [out :: web1.example.com] GNU/Linux

Join multiple machine names with commas (e.g. web1.example.com,web2.example.com).

The above is a bit impractical (you could just SSH to a single machine), but you can also scope to entire role groups using the with keyword:

cap> with web uname -o
 ** [out :: web1.example.com] GNU/Linux
 ** [out :: web2.example.com] GNU/Linux

^
cap> with queue uname -o
** [out :: queue.example.com] GNU/Linux

For more information, see the linked page.

cap invoke

To run shell commands on all servers, you can also use Capistrano's invoke. Its syntax is a bit more complicated:

$ cap staging invoke COMMAND='uname -o'
 ** [out :: web1.example.com] GNU/Linux
 ** [out :: web2.example.com] GNU/Linux
 ** [out :: queue.example.com] GNU/Linux

Note the COMMAND environment variable which must hold the command(s) you want to run.
As mentioned above, if you want to run multiple commands, you need to chain them:

$ cap staging invoke COMMAND='cd /tmp && pwd'
 ** [out :: web1.example.com] /tmp
 ** [out :: web2.example.com] /tmp
 ** [out :: queue.example.com] /tmp

Note that you probably should not use these commands for complex shell operations.
Instead, maybe create a file that does things for you and run that one instead. Or try an application like Terminator Show archive.org snapshot that allows sending the same keystrokes to multiple machines.

Arne Hartherz
August 05, 2013Software engineer at makandra GmbH
Posted by Arne Hartherz to makandra dev (2013-08-05 15:36)