Skip to content

Instantly share code, notes, and snippets.

@acidlabs-snippets
Created October 4, 2012 16:15
Show Gist options
  • Save acidlabs-snippets/3834683 to your computer and use it in GitHub Desktop.
Save acidlabs-snippets/3834683 to your computer and use it in GitHub Desktop.
Rails 3.1+ Multistage deployment with Capistrano #rails #deployment #capistrano
### This gist outlines a generic implementation of multistage deployment with Capistrano for Rails 3.1+.
#
# Usage:
#
# cap #{stage} deploy:setup
# cap #{stage} deploy:cold
# cap #{stage} deploy
#
# etc.
# Gemfile
# ---
gem 'capistrano'
gem 'foreman'
# ---
# Capfile
# ---
load 'deploy'
# If you don't want assets pipiline support, comment the line below
load 'deploy/assets'
Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
load 'config/deploy'
# ---
# config/environments/orange.rb,
# config/environments/lemon.rb
# ---
# copy+paste production.rb
# ---
# config/procfile/orange
# ---
# If you like thin, this'd go like below.
web: nohup bundle exec thin -C ../thin/orange.yml start
# ---
# config/procfile/lemon
# ---
# Ah! I knew it, you like unicorns! Well then, as below for ya' unicorny fella'.
web: nohup bundle exec unicorn -c ../unicorn/lemon.rb -D
# ---
# config/deploy/orange.rb
# ---
# Server Settings. The port is optional, default to 22.
server "awesome.acid.cl:22", :web, :app, :db, primary: true
# User in the remote server. This is the user who's going to be used to deploy, and must have proper permissions.
set :user, "awesome"
# Appstage is the name you want the application to have in the server.
# It's used to set the folder name, the upstart config and other nifty stuff.
set :appstage, "awesome.orange"
# Folder in the remote server where the revisions are going to be deployed.
set :deploy_to, "/home/#{user}/#{appstage}"
# The branch that's going to be checked out. Releases are going to be made everytime there's a new revision (+x commits ahead).
set :branch, "orange"
# ---
# config/deploy/lemon.rb
# ---
# Server Settings. The port is optional, default to 22.
server "awesome.acid.cl:22", :web, :app, :db, primary: true
# User in the remote server. This is the user who's going to be used to deploy, and must have proper permissions.
set :user, "awesome"
# Appstage is the name you want the application to have in the server.
# It's used to set the folder name, the upstart config and other nifty stuff.
set :appstage, "awesome.lemon"
# Folder in the remote server where the revisions are going to be deployed.
set :deploy_to, "/home/#{user}/#{appstage}"
# The branch that's going to be checked out. Releases are going to be made everytime there's a new revision (+x commits ahead).
set :branch, "lemon"
# ---
# ./config/deploy.rb
# ---
require "bundler/capistrano"
# Enable multistage.
require "capistrano/ext/multistage"
# Declare the stages. The stages should follow the names you gave them in config/environments/* .
set :stages, %w(orange lemon)
# Set the default stage
set :default_stage, "lemon"
# The application name is used to determine what repository to pull from, name databases and other nifty stuff.
set :application, "awesome"
# Use sudo when deploying the application. Dunno what's default but true is evil.
set :use_sudo, false
# Choose the Source Control Management tool of your preference.
# (Don't. Really. Use git).
set :scm, :git
# Set the repository we're going to pull from.
# (Sorry, no multirepo, just multistage).
set :repository, "git@git.acid.cl:#{application}.git"
# Setup the way you want the deploy to be done. I sincerely suggest using :remote_cache.
set :deploy_via, :remote_cache
# Pseudo Terminals. If you want password prompt to work this must be true.
default_run_options[:pty] = true
# Imagine you ask a friend to give you his car keys to drive it by yourself.
ssh_options[:forward_agent] = true
set :database_username, user
set :database_password, "weloveacid"
namespace :deploy do
desc "Export the foreman config file to upstart"
task :generate_upstart, roles: :app, except: { no_release: true } do
run [
"cd #{current_release}",
"bundle exec foreman export upstart /tmp -u #{user} -a #{appstage} -f ./config/foreman/#{rails_env} -l #{shared_path}/log"
].join(" && ")
sudo "[ -f /etc/init/#{appstage}.conf ] || exit 0"
sudo "rm -f /etc/init/#{appstage}*.conf"
sudo "mv /tmp/#{appstage}*.conf /etc/init/"
end
desc "Stop the services"
task :stop, roles: :app, except: { no_release: true } do
sudo "[ -f /etc/init/#{appstage}.conf ]"
sudo "[ $(status #{appstage} | grep -c running) -eq 1 ]"
sudo "stop #{appstage} || exit 0"
end
desc "Start the services"
task :start, roles: :app, except: { no_release: true } do
sudo "[ -f /etc/init/#{appstage}.conf ]"
sudo "[ $(status #{appstage} | grep -c running) -eq 0 ]"
sudo "start #{appstage}"
end
desc "Restart the services"
task :restart, roles: :app, except: { no_release: true } do
stop
generate_upstart
start
end
desc "Create database yaml in shared path"
task :db_configure do
db_config = <<-EOF
#{rails_env}:
adapter: postgresql
database: #{application}_#{rails_env}
pool: 25
username: #{database_username}
password: #{database_password}
EOF
run "mkdir -p #{shared_path}/config"
put db_config, "#{shared_path}/config/database.yml"
end
desc "Make symlink for database yaml"
task :db_symlink do
run "ln -snf #{shared_path}/config/database.yml #{latest_release}/config/database.yml"
end
desc "Setup de database"
task :db_setup, :roles => :app do
run [
"cd #{current_path}",
"bundle exec rake db:setup RAILS_ENV=#{rails_env}"
].join(" && ")
end
task :cold do
update
db_configure
db_symlink
db_setup
migrate
generate_upstart
start
end
end
# Before hooks. You can define your own too.
before "deploy", "deploy:db_symlink"
before "deploy:migrations", "deploy:db_symlink"
before "deploy:db_setup", "deploy:db_symlink"
# ---
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment