Capistrano Deploy with Git and Passenger

One of the great things about Rails and its community is that they are very lazy. Lazy in the good way of not wanting to do boring, repetitive, error prone things manually. They metaprogram and they automate. A great example of this is Capistrano. Capistrano allows you to deploy Rails applications with ease. The normal scenario is baked into Capistrano as a deployment convention and then you can customize it if you need to.

My Story

I’ve recently redeployed a couple of Ruby on Rails sites using Passenger (mod_rails). Passenger is an Apache module that really simplifies the deployment of small-scale Rails applications. Once Passenger is installed and your Rails application is set up as a virtual directory, it just works. Passenger auto-detects the fact that the directory is a Rails application and runs it for you. No need for a mongrel cluster or manually configuring load balancing.

I’m also using Git as my version control system on small, personal projects because it’s easy to use and I can work on multiple laptops and commit locally and worry about pushing to a central location when I have a network connection.

Seeing those things, I wanted to make them all work with Capistrano so that I could continue being lazy. To do this, I’m using Capistrano v2.4. It has Git support built in that works (some previous versions had support for Git, but seemed to have a lot of trouble).

Git Setup

By convention, Capistrano uses Subversion. So, I need to change my configuration to use git. The set :scm, :git does this. The repository information sets up where my git repository lives. In this case, I’m just using a bare git repository accessing it over SSH. You can also access your repository using the git and http protocols if you have that setup. The branch just says to deploy off of the master branch.

That’s pretty much it – nice and easy.

set :scm, :git
set :repository, "geoff@zorched.net:myapp.git"
set :branch, "master"
set :deploy_via, :remote_cache

Passenger (mod_rails) Setup

The only thing that comes into play with Passenger is restarting the Rails application after a deployment is done. Passenger has an easy way to do this which is just to create a file called restart.txt in the Rails tmp directory. When it sees that, the Rails application process will be recycled automatically.

Doing this requires just a bit of Capistrano customization. We need to override the deploy:restart task and have it run a small shell script for us. In this case we are running run “touch #{current_path}/tmp/restart.txt” to accomplish this task.


namespace :deploy do
desc "Restarting mod_rails with restart.txt"
task :restart, :roles => :app, :except => { :no_release => true } do
run "touch #{current_path}/tmp/restart.txt"
end

We can also override the start and stop tasks because those don’t really do anything in the mod_rails scenario like they would with mongrel or other deployments.

[:start, :stop].each do |t|
desc "#{t} task is a no-op with mod_rails"
task t, :roles => :app do ; end
end
end

The Whole Thing

Putting everything together in my deploy.rb looks like the following:

set :application, "enotify"

# If you aren't deploying to /u/apps/#{application} on the target
# servers (which is the default), you can specify the actual location
# via the :deploy_to variable:
set :deploy_to, "/var/www/myapp"

# If you aren't using Subversion to manage your source code, specify
# your SCM below:
set :scm, :git
set :repository, "geoff@zorched.net:myapp.git"
set :branch, "master"
set :deploy_via, :remote_cache

set :user, 'geoff'
set :ssh_options, { :forward_agent => true }

role :app, "zorched.net"
role :web, "zorched.net"
role :db, "zorched.net", :primary => true

namespace :deploy do
desc "Restarting mod_rails with restart.txt"
task :restart, :roles => :app, :except => { :no_release => true } do
run "touch #{current_path}/tmp/restart.txt"
end

[:start, :stop].each do |t|
desc "#{t} task is a no-op with mod_rails"
task t, :roles => :app do ; end
end
end

15 thoughts on “Capistrano Deploy with Git and Passenger”

  1. Thanks a lot! I’ll try this out right now and will get back with more comments about how I fared. Keep up the sharing!

  2. Nice write up! However, I was wondering if the setup was the same if you have multiple repositories you are deploying. I have multiple repos and am able to deploy to one of them with no problem, however I am getting a “repository not found” when trying to deploy to another. In the error, the repo name it is trying to access is correct and I am able to push changes with no problem ( I see the commit in github). Any ideas regarding why I may be seeing this? Here is the error message, any help would be greatly appreciated! * executing `deploy:update’ ** transaction: start * executing `deploy:update_code’ updating the cached checkout on all servers executing locally: “git ls-remote git@github.com:sfolks/exsellintcrm.git master” * executing “if [ -d /home/neo/apps/exsellintcrm/shared/cached-copy ]; then cd /home/neo/apps/exsellintcrm/shared/cached-copy && git fetch -q origin && git reset -q –hard 69335a40b5f37071f6fa2436b587a48fae4629c6; else git clone -q git@github.com:sfolks/exsellintcrm.git /home/neo/apps/exsellintcrm/shared/cached-copy && cd /home/neo/apps/exsellintcrm/shared/cached-copy && git checkout -q -b deploy 69335a40b5f37071f6fa2436b587a48fae4629c6; fi” servers: ["exsellintcrm.com"] Password: [exsellintcrm.com] executing command ** [exsellintcrm.com :: out] Repository not found. If you’ve just created it, please try again in a few seconds. ** [exsellintcrm.com :: out] fatal: The remote end hung up unexpectedly command finished *** [deploy:update_code] rolling back * executing “rm -rf /home/neo/apps/exsellintcrm/releases/20090525030837; true” servers: ["exsellintcrm.com"] [exsellintcrm.com] executing command command finished failed: “sh -c \”if [ -d /home/neo/apps/exsellintcrm/shared/cached-copy ]; then cd /home/neo/apps/exsellintcrm/shared/cached-copy && git fetch -q origin && git reset -q –hard 69335a40b5f37071f6fa2436b587a48fae4629c6; else git clone -q git@github.com:sfolks/exsellintcrm.git /home/neo/apps/exsellintcrm/shared/cached-copy && cd /home/neo/apps/exsellintcrm/shared/cached-copy && git checkout -q -b deploy 69335a40b5f37071f6fa2436b587a48fae4629c6; fi\”" on exsellintcrm.com

  3. Pingback: kenny's me2DAY
  4. Thanks man. That really helped having an updated Capistrano recipe for Git/Passenger. Another one I was using was giving me some error because it was trying to run script/process/reaper

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>