Capistrano 2.0, upgrading & fitting into a size 0 dress
Posted by Mathew Abonyi Fri, 27 Jul 2007 14:02:09 GMT
The improvements to Capistrano are much welcomed. My deployment recipe is now half the length it used to be and it is much easier to follow what is happening for my many types of deployment. I love the new features added, mostly dealing with manipulating scopes and enhancing the user’s ability to extend the core framework.
Review of new features
namespaces: Like Rake, you can namespace your tasks and group them together more sensibly. This feature alone is worth upgrading for just to make your scripts more sensible and easier to read.
events: Like Rails, you can now perform tasks before or after other ones rather than using the hacky ‘before_something’ and ‘after_something’. Much cleaner and much faster too.
strategies: In addition to checkout, you can now deploy via export and copy and use different strategies for deployment, such as using export for your copy_strategy rather than zips and tarballs.
scoping: All sorts of scoping has been introduced in Capistrano 2.0, from namespacing to single execution of “run” and “sudo”, allowing you to define specific roles or hosts in which your commands run.
help: Capistrano 2.0 now has a more verbose way of explaining tasks with cap -e task_name. You’ll realise how useful this is when you use it for the built-ins as well as your own.
All in all, Capistrano is pretty simple, but it is the way it is written that makes it appear so much simpler than it really is. Capistrano 2.0 takes that to a new level, not groundbreaking perhaps, but definitely a lot cleaner than its previous releases.
Upgrading from 1.4.1
There is no need to change config/deploy.rb out of the box. Capistrano 2.0 is nicely backwards compatible, unlike other things out there, and, at least for me, nothing broke because of the upgrade.
You can look at Capistrano’s instructions for upgrading, if you want to know what is being done, but for the impatient, here are the steps you have to follow before we can start drying up your deploy script.
1. Install the new version of capistrano:sudo gem install capistrano~# cd projroot
projroot# capify .projroot# cap -f upgrade -f Capfile upgrade:revisions4. Rinse and repeat for each of your deployment targets
Getting your deploy.rb into its new size 0 dress
You may now have the very understandable urge to slim down your deployment recipes. With the introduction of Capistrano 2.0, I found my deploy.rb reduced to less than half the size. Below, I cover the areas which you should focus on to get that deploy script into its new size 0 dress.
Anatomy of my deploy.rb
- requires: capistrano-ext, mongrel_cluster, etc.
- global, stage and custom variables
- event chains
- rewriting built-ins: web:disable and web:enable
- extra tasks: fixing permissions, copying mongrel confs, etc.
- custom deploy tasks: long, normal, quick
- maintenance tasks: backup, restore
Variables
More than before, variables are the lynch-pin of slimming everything down. The first thing you should do is look over every task rewrite or custom task and see how it can be turned into a simple set :var, true/false/whatever. Capistrano 2.0 will make it very easy to do this.
With Capistrano 2.0, you should use the set command religiously, both for built-in and custom tasks.
I personally set the following at the top of my recipe.
- Global variables: stages, deploy_via
- Application specific: application, repository, user, scm_username
- Deployment specific: deploy_to, rails_env
- Custom variables: serving_via, suexec, suexec_user, suexec_group, disable_template
Deployment Strategy
I would personally suggest using xport for your deploy_via strategy unless you have a reason for using heckout or copy.
Using Namespaces
Namespaces make it dead simple to group common tasks, like different restart methodologies. I use a serving_via variable which translates into the reload:whatever task to run for restarting the application. For example:
namespace :reload do
desc "Default reloading procedure"
task :default do
mongrels
end
desc "Reload an FCGI application"
task :fcgi, :roles => :app do
sudo "#{current_path}/script/process/reaper -a graceful -d #{current_path}/public/dispatch.fcgi"
end
desc "Reload an LSAPI application"
task :lsapi, :roles => :app do
sudo "/usr/local/litespeed/bin/lswsctrl restart"
end
desc "Give the mongrels a bath"
task :mongrels, :roles => :app do
restart_mongrel_cluster
end
endNote: I warn against using restart as a namespace because it clashes with the built-in task and, in certain instances, results in infinite recursion.
Maintenance Splash
The biggest change in Capistrano you may need to worry about is the removal of delete and render. Don’t despair, though, because creating a maintenance splash is still easy. This is my rewrite:
desc "Generate a maintenance.html to disable requests to the application."
deploy.web.task :disable, :roles => :web do
remote_path = "#{shared_path}/system/maintenance.html"
on_rollback { run "rm #{remote_path}" }
template = File.read(disable_template)
deadline, reason = ENV["UNTIL"], ENV["REASON"]
maintenance = ERB.new(template).result(binding)
put maintenance, "#{remote_path}", :mode => 0644
end
desc "Re-enable the web server by deleting any maintenance file."
deploy.web.task :enable, :roles => :web do
run "rm #{shared_path}/system/maintenance.html"
endUsing events
Like the before and after filters in Rails, you can now cleanly chain together tasks. I’m a sucker for one-line solutions and these are really so simple that it makes my heart bleed:
before "deploy:restart", "fix:permissions"
before "deploy:migrate", "db:backup"
after "deploy:symlink", "deploy:cleanup"
after "deploy:update_code", "deploy:web:disable"
after "deploy:restart", "deploy:web:enable"capistrano-ext & multistage
I highly recommend the use of multistage. It comes with the capistrano-ext gem (which has been upgraded to Capistrano 2.0, of course).
Basically, it separates the concerns of different deployments. If, like me, you like having a few other versions of your application out there, like a staging area, a testing area for bleeding edge features, and, of course, the production site, separating these in Capistrano before 2.0 was very irritating. Multistage sorts that out very nicely.
By default, you must specify the stage you wish to deploy. This behaviour can be overridden by setting the default_stage variable, but I like being explicit. This is what using stages looks like:
# cap production deployIf you don’t provide ‘production’, it’ll complain and abort.
Using multistage is dead easy. Put this at the top of your deploy.rb:
require 'capistrano/ext/multistage'
set :stages, %w(staging production testing)Run the task for generating your stage deploy files:
projroot# cap multistage:prepareThis will create a recipe file for each stage in a new config/deploy directory (exactly like Rails environments). Now, in each stage recipe, add all of your stage-specific tasks and variables. For example:
set :rails_env, "stage"
set :application, "staging.example.com"
set :deploy_to, "/var/www/#{application}"Now switching between different deployments is a breeze. Just make a new recipe file for it with the necessary variables and you’re set.

What do you have “disable_template” set to? Better yet, do you have your deploy.rb available to download? You can change the passwords and repo addresses. I just want to figure out how to do rewrite web:disable. I try it and it tries to render the template on my local computer.