Skip to content

2.x Multistage Extension

mcmire edited this page · 20 revisions

Capistrano's multistage extension provides an easy way to use a different deployment strategy for different scenarios. For instance, for your application, you might have two servers: one for production, where the "live" code is, and one for staging, where you can test features out without risk of affecting anything critical. Certain deployment values, such as the application name, UNIX user and group, and application environment might be the same, but other values might be different, such as the location of the server itself or the SCM repository branch. Instead of repeating code in your Capfile, you can use multistage to set the values which are different in separate files, and only load those files at runtime.

This article will walk you through installing and using the multistage extension. We're going to use the example we mentioned earlier, where we have a production server and a staging server. So naturally, we would like two deployment stages, production and staging. We also assume you're creating an application from scratch.

Installation

The multistage extension actually lives within the capistrano-ext gem. So first let's install Capistrano itself and then that:

gem install capistrano capistrano-ext

Then, let's make a directory for our application:

mkdir ~/apps/capistrano-multistage-test
cd ~/apps/capistrano-multistage-test

Next we'll want to create a config directory to house our custom stage files:

mkdir -p config/deploy

Now open the usual Capistrano deployment file, Capfile, and enter this content:

set :stages, %w(production staging)
set :default_stage, "staging"
require 'capistrano/ext/multistage'

set :application, "capistrano-multistage-test"
set :user, "www-data"
set :group, "www-data"

set :scm, :git
set :repository, "ssh://ourserver/#{application}.git"
set :deploy_to, "/var/www/#{application}"
set :deploy_via, :remote_cache
set :deploy_env, 'production'

What does this do? Well, first we tell Capistrano what our stages are. This will allow us to say cap production TASK or cap staging TASK to run a task within a specific stage. We also set the default stage to "staging", that way we can simply say cap TASK and it will execute the task within the "staging" stage by default. Then, we bring in the multistage code (yes, after we configure the stages; it just the way the extension works). Finally, we set some variables that will be common to our stages.

Let's also write a small task that we can use to test our stages:

task :uname do
  run "uname -a"
end

So that takes care of your main config file. What about the stages themselves? Well, when you say cap my_stage TASK (for instance), Capistrano looks for a file config/deploy/my_stage.rb and loads it. It's in this file that you configure the variables and tasks that apply to that stage.

So we need to create two files, config/deploy/production.rb and config/deploy/staging.rb. In config/deploy/production.rb, we might have this:

server 'production.server.com', :app, :web, :primary => true

And in config/deploy/staging.rb we might have this:

server 'staging.server.com', :app, :web, :primary => true

That's it. If we were now to run cap production uname, the uname task would get executed on production.server.com; if we were to run cap staging uname, it would get run on staging.server.com.

It's worth nothing that anything we would normally put in our Capfile, we can also put in our stage files. So if, say, we were using Nginx + Unicorn on our production server but Apache on our staging server, we could override the deploy:restart task only for the production stage by putting this in config/deploy/production.rb:

namespace :deploy do
  task :start do
    # ...
  end

  task :stop do
    # ...
  end

  task :restart do
    # ...
  end
end

Caveats

Don't name your stage "stage", as this is a reserved word under the multistage extension (deploys won't do anything and in fact it will cause an infinite loop).

Alternatives

Something went wrong with that request. Please try again.