capistrano-multiproject

Author: Olek Poplavsky

Introduction

Capistrano extension that allows to deploy multiple projects from one location.

Everybody knows/uses original multistage extension written by Jamis Buck. It works great while you have only one project/app to deploy. It is not quite enough if you have multiple projects to deploy (SOA would be one big use case here). Capistrano-multiproject solves this problem by allowing splitting up deploy.rb into multiple project-specific recipe files.

Installation

Install gem

$ gem install capistrano-multiproject

Setup

You are expected to create separate project, whole purpose of which is to deploy other projects. That may be just a directory in your source repository, or a separate repository, it is up to you.

Typical directory structure of 'deploy' project

config/
  deploy/
    projects/
      project1.rb
      project2.rb
    stages/
      testing.rb
      qa.rb
      demo.rb
      production.rb
  deploy.rb
recipes/
  recipe1.rb
  recipe2.rb
Capfile
Gemfile

Usage

If your run 'cap -T' you will see that only tasks that are loaded by default are projects, stages, and strange '?' task. That last one is actually a replacement for '-T' option, that is customized for the multiproject setup.

'cap ?' outputs list of stages.

'cap stage1 ?' outputs list of projects.

'cap stage1 project1 ?' outputs list of capistrano tasks available in a given project.

'cap stage1 project1 task1' executes capistrano task for some project in a context of given stage.

Configuration

Add to Gemfile

gem 'capistrano'
gem 'capistrano-multiproject'

Add to Capfile

require 'capistrano/multiproject'
load 'config/deploy'

Create file config/deploy.rb. Put you common settings/recipes there, those will be shared by all projects. Settings like 'scm', 'repository', 'use_sudo', 'ssh_options' are good candidates to put here. Require common shared recipes like this:

load 'recipes/recipe1.rb'

Create directories deploy/projects and deploy/stages.

Stages directory contains .rb files that describe settings particular to specific stage. Usually all that is done here is setting branch (or repository) and bunch of server roles.

Example of stage file config/deploy/stages/stage1.rb:

role :app, 'app1.foo.com', 'app2.foo.com'
role :redis, 'misc.foo.com'
role :shpinx, 'misc.foo.com'
role :db, 'masterdb.foo.com', :primary => true, :master => true
role :db,  'slavedb.foo.com', :no_release => true, :master => false
set :branch, 'master'

Projects directory contains .rb files that contains recipes specifit to particular project.

Example config/deploy/projects/foo.rb:

load 'recipes/recipe1.rb'

set :shared_children, %w(log pids)

namespace :deploy  do
  desc "Stops foo service"
  task :stop do
    run "#{sudo} /etc/init.d/foo stop"
  end

  desc "Starts foo service"
  task :start do
    run "#{sudo} /etc/init.d/foo start"
  end

  desc "Restarts foo service"
  task :restart do
    run "#{sudo} /etc/init.d/foo restart"
  end
end

By default, only roles that are named the same as project file, are loaded (that is, for project 'foo.rb', only role 'foo' will be loaded, roles 'db', 'redis' etc will not make it to capistrano. When this needs to be customized, it is easy to do that my setting property project_roles like this:

set :project_roles, ['role1', 'role2']

In addition to roles defined in stage file, project's recipes have access to one special/synthetic 'any_server' role. That role contains all the servers that were defined in the stage file, combined. It is very useful to implement some administration recipes, like 'reboot all servers', 'update ubuntu software on all servers', or 'run chef-client on all servers'.

Example config/deploy/projects/admin.rb:

set :project_roles, %w(any_server)
namespace :servers do
  namespace :reboot do
    desc "Reboot all servers"
    task :all do
      run "#{sudo} shutdown -r +1" # reboot in 1 minute
    end
  end
end

Compatibility

Tested against MRI 1.9.3 and 1.8.7.

License

capistrano-multiproject is released under the MIT license.

Credits

Jamis Buck

capistrano-multistage started it all

Andriy Yanko

caphub and capistrano-multiconfig were the inspiration for this project