Using Capistrano

“We will encourage you to develop the three great virtues of a programmer: laziness, impatience, and hubris.”—Larry Wall, Programming Perl
Finding More

To deploy our application, we used only deploy:setup, deploy:cold and deploy. The recipe has a lot more in it. To see all the available tasks, run:

cap -Tv

Much like rake -T, this lists all the tasks with their documentation. If you've run deploy a few times, play with either of the rollback or rollback_code tasks.

Each time you roll back, Capistrano simply points the symlink to the previous deployment's directory. Rollbacks can be run repeatedly until you find the stable version you want:

cap deploy:rollback_code

Your Own Tasks

Once you get Capistrano working on a Rails project, it's easy to see how it could help make your life really lazy. The same kind of tasks that wrap around Rails-specific commands can contain pretty much any command.

When you run Capistrano tasks, like deploy, you'll see various SSH commands and responses scroll by. If you have several servers, the responses will come back from multiple servers as Capistrano runs your tasks across as many machines as you need.

The potential uses of this are huge—checking disk space, copying live data from clusters and running maintenance tasks—so how can we build our own tasks?

Tasks in Capistrano are defined with the following syntax:

desc "Short description here..."
task :name_of_function, :roles => :servers do
        # tasks is in here...

Ruby's elegant syntax often makes things confusingly simple, so let's pick it apart. The first line provides some documentation that is output when you run the following on the command line (still from the root of your project):

cap -Tv

Ruby can cope without brackets when calling functions, so the second line actually is a call to Capistrano's task function.

The first argument is the new task's name (name_of_function). The second is the set of machines on which the task will be run; this can be either :servers, :app, :db or any other collection of servers you have.

The last part, starting at do, is an anonymous function, which means that everything between do and end is executed when your task is run. You may have come across anonymous functions in JavaScript.

A very simple task would be to run df -h on the remote servers to check on disk space. This isn't going to change anything on your servers, so you should feel safe running it:

desc "Check disk space"
task :diskspace, :roles => :servers do
        run 'df -h'

The run function simply runs the command on the remote servers. You can replace this with sudo, which also does what it sounds like—runs remote commands under sudo:

desc "Who hasn't been cleaning out their home directories?"
task :home_disk_usage, :roles => :servers do
        sudo 'du -sh /home/*'

If you have capified a project as we did on the Rails project in the previous section, you even can add your own custom tasks to the standard Rails recipe and change the behaviour of the Rails recipe itself. This lets you get Capistrano working just as you need it to work, and it's is good for those commands you never can remember how to run!

To add your own tasks to a capified Rails project, add them to config/deploy.rb using the task syntax described above. Once you have added a task, run cap -Tv to check whether your task was found, and then run the task as you would any other.

Tasks can call each other just like functions can, so complex tasks can be broken down into simple tasks that will keep your custom Capistrano recipes “DRY”. Tasks can call each other using the normal Rails function call:

task :home_disk_usage, :roles => :servers do
        run "ls /home/"

You'll probably want your customised tasks to know the location in the filesystem where your project is being deployed. This is a matter of using the configuration variables we set right at the beginning, which can be done using the Ruby syntax:

run "tar czf ~/snapshot.tgz #{release_path}"

If you need additional variables, you can set them using the same syntax as before:

set :foo, "bar"

Alternatively, you can prompt the user for the variables by using the set function, but with a slightly different usage:

set(:deploy_version) do
        Capistrano::CLI.ui.ask "What version is this? "

The variables are used in the same way, no matter which method is used to set them.

All this Ruby should start falling into place, and by this point, you'll start thinking of Capistrano as a Ruby framework rather than a standalone application or script. If Ruby is new to you, keep going—it'll start dropping into place soon.

Finally, it's nice to keep things neat as well as DRY. All of the Rails recipes are found in the deploy namespace, which you'll notice when you run cap -Tv. Namespaces allow you to group tasks together, and this can be done by wrapping the tasks in the namespace command:

namespace :our_tasks do
  desc "The default task"
  task :default do
  desc "Empty logs"
  task :empty_logs do
        # ...

When you run cap -Tv, you'll see these neatly grouped:

cap our_tasks            # The default task
cap our_tasks:empty_logs # Empty logs



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

cap'ing Rails projects on servers

Walther Diechmann's picture

Hi Dan,

nice article - do you have any 'advanced' setups, like this one?

role :app, "", :primary => true, :user => "root"
role :web, ""
role :db, ""
set :gateway, "webserver.domain.tld"

set :repository, "git@{application}.git"


Because I cannot get my multistage deploy to work :)

All the blogs and articles I've come around, they all seem to focus on setups with all servers on one machine, and git somewhere entirely else (like

Best regards,