Skip to content

Instantly share code, notes, and snippets.

@andreaseger
Last active December 21, 2015 16:49
Show Gist options
  • Save andreaseger/6336096 to your computer and use it in GitHub Desktop.
Save andreaseger/6336096 to your computer and use it in GitHub Desktop.
rails deploy w/ rvm, bundler, unicorn
# Automatically precompile assets
load "deploy/assets"
# Execute "bundle install" after deploy, but only when really needed
require "bundler/capistrano"
# Application name
set :application, "page"
# Application environment
set :rails_env, :production
# Deploy username and sudo username
set :user, "deployer"
set :user_rails, "rails"
# App Domain
set :domain, "example.com"
# We don't want to use sudo (root) - for security reasons
set :use_sudo, false
# Target ruby version
set :rvm_ruby_string, 'ruby-2.0.0-p195-turbo@gemset'
# System-wide RVM installation
set :rvm_type, :system
# We use sudo (root) for system-wide RVM installation
set :rvm_install_with_sudo, true
# RVM integration
require "rvm/capistrano"
# git is our SCM
set :scm, :git
# Use github repository
set :repository, "[email protected]:sch1zo/repo.git"
# master is our default git branch
set :branch, "master"
# Deploy via github
set :deploy_via, :remote_cache
set :deploy_to, "/srv/http/#{application}"
# We have all components of the app on the same server
server domain, :app, :web, :db, :primary => true
# Install RVM and Ruby before deploy
before "deploy:setup", "rvm:install_rvm"
before "deploy:setup", "rvm:install_ruby"
# Apply default RVM version for the current account
after "deploy:setup", "deploy:set_rvm_version"
# copy settings
before "deploy:update_code", "deploy:copy_settings"
before "deploy:assets:precompile", "deploy:fix_symlinks"
# Fix log/ and pids/ permissions
after "deploy:setup", "deploy:fix_setup_permissions"
# Fix permissions
before "deploy:start", "deploy:fix_permissions"
after "deploy:restart", "deploy:fix_permissions"
after "deploy:assets:precompile", "deploy:fix_permissions"
# Clean-up old releases
after "deploy:restart", "deploy:cleanup"
# Unicorn config
set :unicorn_config, "#{current_path}/config/unicorn.rb"
set :unicorn_binary, "bash -c 'source /etc/profile.d/rvm.sh && cd #{current_path} && bundle exec unicorn_rails -c #{unicorn_config} -E #{rails_env} -D'"
set :unicorn_pid, "#{current_path}/tmp/pids/unicorn.pid"
set :su_rails, "sudo -u #{user_rails}"
namespace :deploy do
task :start, :roles => :app, :except => { :no_release => true } do
# Start unicorn server using sudo (rails)
run "#{su_rails} #{unicorn_binary}"
end
task :stop, :roles => :app, :except => { :no_release => true } do
run "if [ -f #{unicorn_pid} ]; then #{su_rails} kill `cat #{unicorn_pid}`; fi"
end
task :graceful_stop, :roles => :app, :except => { :no_release => true } do
run "if [ -f #{unicorn_pid} ]; then #{su_rails} kill -s QUIT `cat #{unicorn_pid}`; fi"
end
task :reload, :roles => :app, :except => { :no_release => true } do
run "if [ -f #{unicorn_pid} ]; then #{su_rails} kill -s USR2 `cat #{unicorn_pid}`; fi"
end
task :restart, :roles => :app, :except => { :no_release => true } do
stop
start
end
task :set_rvm_version, :roles => :app, :except => { :no_release => true } do
run "source /etc/profile.d/rvm.sh && rvm use #{rvm_ruby_string} --default"
end
task :fix_setup_permissions, :roles => :app, :except => { :no_release => true } do
run "#{sudo} chgrp #{user_rails} #{shared_path}/log"
run "#{sudo} chgrp #{user_rails} #{shared_path}/pids"
end
task :fix_permissions, :roles => :app, :except => { :no_release => true } do
# To prevent access errors while moving/deleting
run "#{sudo} chmod 775 #{current_path}/log"
run "#{sudo} find #{current_path}/log/ -type f -exec chmod 664 {} \\;"
run "#{sudo} find #{current_path}/log/ -exec chown #{user}:#{user_rails} {} \\;"
run "#{sudo} find #{current_path}/tmp/ -type f -exec chmod 664 {} \\;"
run "#{sudo} find #{current_path}/tmp/ -type d -exec chmod 775 {} \\;"
run "#{sudo} find #{current_path}/tmp/ -exec chown #{user}:#{user_rails} {} \\;"
run "#{sudo} chgrp #{user_rails} #{shared_path}/uploads -R"
end
task :copy_settings, :roles => :app, :except => { :no_release => true } do
%w(database.yml settings.yml newrelic.yml unicorn.rb).each do |file|
top.upload "config/#{file}", "#{shared_path}/#{file}"
end
end
task :fix_symlinks, :roles => :app, :except => { :no_release => true } do
run "#{sudo} ln -nfs #{shared_path}/uploads #{current_path}/public/u"
run "#{sudo} ln -nfs #{shared_path}/log #{current_path}/log"
run "#{sudo} chown -h #{user}:#{user_rails} #{current_path}/log"
run "#{sudo} chown -h #{user}:#{user_rails} #{current_path}/public/u"
%w(database.yml settings.yml newrelic.yml unicorn.rb).each do |file|
run "#{sudo} ln -nfs #{shared_path}/#{file} #{release_path}/config/#{file}"
end
end
# Precompile assets only when needed
namespace :assets do
task :precompile, :roles => :web, :except => { :no_release => true } do
# If this is our first deploy - don't check for the previous version
if remote_file_exists?(current_path)
from = source.next_revision(current_revision)
if capture("cd #{latest_release} && #{source.local.log(from)} vendor/assets/ app/assets/ | wc -l").to_i > 0
run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile}
else
logger.info "Skipping asset pre-compilation because there were no asset changes"
end
else
run %Q{cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile}
end
end
end
end
task :refresh_sitemaps do
run "cd #{latest_release} && RAILS_ENV=#{rails_env} rake sitemap:refresh:no_ping"
run "#{sudo} chgrp #{user_rails} #{current_path}/public/sitemap.xml.gz"
run "#{sudo} chmod 775 #{current_path}/public/sitemap.xml.gz"
#run "#{sudo} chgrp #{user_rails} #{current_path}/public/sitemap_index.xml.gz"
#run "#{sudo} chmod 775 #{current_path}/public/sitemap_index.xml.gz"
end
#before ["deploy:start", "deploy:restart"] do
# refresh_sitemaps
#end
task :recreate_carrierwave do
run "cd #{latest_release} && RAILS_ENV=#{rails_env} rake carrierwave:recreate_all"
end
# Helper function
def remote_file_exists?(full_path)
'true' == capture("if [ -e #{full_path} ]; then echo 'true'; fi").strip
end
# 4 workers is enough for our app
worker_processes 4
# App location
@app = "/srv/http/page/current"
# Listen on fs socket for better performance
listen "#{@app}/tmp/sockets/unicorn.sock", :backlog => 64
# Nuke workers after 30 seconds instead of 60 seconds (the default)
timeout 30
# App PID
pid "#{@app}/tmp/pids/unicorn.pid"
# By default, the Unicorn logger will write to stderr.
# Additionally, some applications/frameworks log to stderr or stdout,
# so prevent them from going to /dev/null when daemonized here:
stderr_path "#{@app}/log/unicorn.stderr.log"
stdout_path "#{@app}/log/unicorn.stdout.log"
# To save some memory and improve performance
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true
# Force the bundler gemfile environment variable to
# reference the Сapistrano "current" symlink
before_exec do |_|
ENV["BUNDLE_GEMFILE"] = File.join(@app, 'Gemfile')
end
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
end
after_fork do |server, worker|
# the following is *required* for Rails + "preload_app true",
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment