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