Author: Olek Poplavsky
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.
Install gem
$ gem install capistrano-multiproject
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
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.
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
Tested against MRI 1.9.3 and 1.8.7.
capistrano-multiproject is released under the MIT license.
Jamis Buck
capistrano-multistage started it all
Andriy Yanko
caphub and capistrano-multiconfig were the inspiration for this project