Deployment with Vlad

Application deployment based on Rake

When I ask people about how they deploy their Rails apps, most of them answer that they are using good old Capistrano. It is the most popular solution because it has been around since almost when people started deploying Rails applications and it works well in most cases. However, if you want to do a lot of custom tasks and need to look under the hood to extend it, Capistrano seems somewhat complicated. At least it did at the time I left it in favor of Vlad - an imho more intuitive deployment tool.

Though one might not like the offense against Capistrano that was shown when Vlad was released in 2007, it addresses some valid points when arguing against needless complexity. But enough of the history, this was almost five years ago, both of the tools have improved, made their way and all I wanted to share is some snippets and insights I got from using Vlad over the last years.

The main thing I like abot Vlad is that it is based on Rake, which makes it so easy to learn, understand and extend. If you want to do something custom, all you have to do is to write a Rake task. And as you will want to use them across different projects, you can even bundle them up and distribute them as a gem, like I’ve done with vlad-extras, a set of extensions for tools like DelayedJob, ThinkingSphinx, Monit, Whenever and so on.

Here is what a simple config/deploy.rb file might look like:

# Custom variables used in the following config
set :application, "appname"

# Required variables
set :domain, "#{application}.com"
set :deploy_to, "/var/www/#{application}"
set :repository, "git@github.com:myaccount/#{application}.git"

# Optional variables
set :user, "deploy" # if different from your current login
set :bundle_cmd, "/usr/local/bin/bundle"
set :rake_cmd, "#{bundle_cmd} exec rake"
set :revision, "origin/master"

# vlad-extras config
set :copy_shared, {
  'config/maintenance.html' => 'config/maintenance.html',
  'config/database.yml'     => 'config/database.yml' }
set :symlinks, {
  'assets'              => 'public/assets',
  'config/database.yml' => 'config/database.yml' }
set :deploy_tasks, %w(
  vlad:maintenance:on
  vlad:update
  vlad:symlink
  vlad:bundle:install
  vlad:assets:precompile
  vlad:migrate
  vlad:start_app
  vlad:maintenance:off
  vlad:cleanup)

# Bundler ships with vlad integration you'll have to require
# in order to use the vlad:bundle tasks
require 'bundler/vlad'

# Require custom vlad tasks or recipes from vlad-extras
require 'vlad/maintenance'

# Some custom tasks, can be included directly in the deploy file
namespace :vlad do
  namespace :custom_script do
    %w(start stop restart).each do |task|
      desc "#{task.capitalize} the custom script"
      remote_task task, :roles => :app do
        run "cd #{current_release}; RAILS_ENV=#{rails_env}
          #{bundle_cmd} exec ruby script/custom #{task}"
      end
    end
  end
end

Here is an example of how easy it is for instance to add staging support:

task :staging do
  set :rails_env, "staging"
  set :deploy_to, "/var/www/#{application}-#{rails_env}"
end

task :production do
  set :rails_env, "production"
  set :deploy_to, "/var/www/#{application}-#{rails_env}"
end

All you need to do is to change some variables based on the environment that is set with a simple Rake task. You’d invoke it by running

$ bundle exec rake staging vlad:deploy

Gemfile

You can include Vlad and it’s requirements in the development group, because it you do not need it in any other environment. Requiring is done in the Rakefile like shown below.

group :development do
  # Deployment
  gem 'vlad', :require => false
  gem 'vlad-git', :require => false
  gem 'vlad-extras', :require => false
end

Rakefile

Add this snippet to your Rakefile, just before MyApp::Application.load_tasks

if Rails.env.development?
  begin
    require 'vlad'
    require 'vlad-extras'
    Vlad.load(scm: :git, web: :nginx, app: :passenger, type: :rails)
  rescue LoadError
    puts 'Could not load Vlad'
  end
end

You might have to configure the options given to Vlad.load.

If you want to get started, take a look at the documentation to find out about the parts that this post leaves out.

Troubleshooting

This part is about some trouble I’ve had and it is not really Vlad specific. You might encounter these problems when trying to deploy to your production server and maybe these tips and links will help.

The deployment shell environment

If Vlad does not find some commands, try the following:

To enable per user PATH environments for ssh logins you need to add to your sshd_config:

PermitUserEnvironment yes

After that, restart sshd!

Then in your users ssh home directory (~/.ssh/environment), add something to this effect (your mileage will vary):

PATH=/opt/ruby-1.9.3/bin:/usr/local/bin:/bin:/usr/bin

For details on that, see this article on setting the deployment shell environment

SSH Agent Forwarding

Maybe you also need to configure SSH Agent Forwarding:

$ ssh-add ~/.ssh/<private_keyname>

Edit your ~/.ssh/config file and add something like this:

Host <name>
  HostName <ip or host>
  User <username>
  IdentityFile ~/.ssh/<filename>
  ForwardAgent yes

For details on that see this article on SSH Agent Forwarding

iPhone app for GitHub

iOctocat

is GitHub in your pocket: The go to app for staying up to date with your projects on your iPhone, and iPod Touch.
It is