Skip to content

Instantly share code, notes, and snippets.

@everaldo
Last active December 20, 2015 07:19
Show Gist options
  • Save everaldo/6092643 to your computer and use it in GitHub Desktop.
Save everaldo/6092643 to your computer and use it in GitHub Desktop.
Unicorn Deploy with Capistrano
## other files ommited
config/deploy.rb
config/unicorn.rb
config/nginx.conf
config/unicorn_init.sh
require "bundler/capistrano"
server "SERVER_ADDRESS", :web, :app, :db, primary: true
set :application, "APP_NAME"
set :user, "APP_USER"
set :deploy_to, "/home/#{user}/apps/#{application}"
set :deploy_via, :remote_cache
set :use_sudo, false
set :scm, "git"
set :repository, "GIT_REPOSITORY"
set :branch, "BRANCH"
set :unicorn_init, "unicorn_APPNAME"
set :pid_path, "#{shared_path}/pids/unicorn.pid"
set :socket_path, "/tmp/APPNAME.unicorn.sock"
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
after "deploy:restart", "deploy:cleanup"
namespace :deploy do
%w[start stop restart].each do |command|
desc "#{command} unicorn server"
task command, roles: :app, except: {no_release: true} do
sudo "service #{unicorn_init} #{command}"
end
end
task :setup_config, roles: :app do
sudo "ln -nfs #{current_path}/config/nginx.conf /etc/nginx/sites-enabled/#{application}"
run "mkdir -p #{shared_path}/config"
## or config/database.yml if you are using ActiveRecord
put File.read("config/mongoid.yml"), "#{shared_path}/config/mongoid.yml"
put File.read("config/unicorn.rb"), "#{shared_path}/config/unicorn.rb"
put File.read("config/nginx.conf"), "#{shared_path}/config/nginx.conf"
put File.read("config/unicorn_init.sh"), "#{shared_path}/config/unicorn_init.sh"
run "cd #{shared_path} && chmod +x config/unicorn_init.sh"
sudo "#ln -nfs #{shared_path}/config/unicorn_init.sh /etc/init.d/#{unicorn_init}"
sudo "#update-rc.d -f #{unicorn_init} defaults"
puts "Now edit the config files in #{shared_path}."
end
after "deploy:setup", "deploy:setup_config"
task :symlink_config, roles: :app do
## or config/database.yml if you are using ActiveRecord
run "ln -nfs #{shared_path}/config/mongoid.yml #{release_path}/config/mongoid.yml"
run "ln -nfs #{shared_path}/config/unicorn.rb #{release_path}/config/unicorn.rb"
run "ln -nfs #{shared_path}/config/nginx.conf #{release_path}/config/nginx.conf"
run "ln -nfs #{shared_path}/config/unicorn_init.sh #{release_path}/config/unicorn_init.sh"
end
after "deploy:finalize_update", "deploy:symlink_config"
desc "Make sure local git is in sync with remote."
task :check_revision, roles: :web do
unless `git rev-parse HEAD` == `git rev-parse origin/BRANCH`
puts "WARNING: HEAD is not the same as origin/BRANCH"
puts "Run `git push` to sync changes."
exit
end
end
before "deploy", "deploy:check_revision"
end
after "deploy:update", "unicorn:restart"
# Unicorn tasks
namespace :unicorn do
def check_pid_path_then_run(command)
run <<-CMD
if [ -s #{pid_path} ]; then
#{command}
else
echo "Unicorn master worker wasn't found, possibly wasn't started at all. Try run unicorn:start first";
fi
CMD
end
desc "Starts the Unicorn server"
task :start do
run "mkdir -p #{File.dirname(pid_path)}"
run "mkdir -p #{File.dirname(socket_path)}"
run <<-CMD
if [ ! -s #{pid_path} ]; then
#{try_sudo} service #{unicorn_init} start
else
echo "Unicorn is already running at PID: `cat #{pid_path}`";
fi
CMD
end
desc "Stops Unicorn server"
task :stop do
run "#{try_sudo} service #{unicorn_init} stop"
end
desc "Zero-downtime restart of Unicorn"
task :restart, :roles => :app, :except => { :no_release => true } do
check_pid_path_then_run "#{try_sudo} kill -USR2 `cat #{pid_path}`;"
end
end
upstream unicorn {
server unix:/tmp/APP_NAME.unicorn.sock fail_timeout=0;
}
server {
listen 80 default deferred;
server SERVER_NAME.COM;
root APP_PATH/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @unicorn;
location @unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
working_directory "APP_PATH"
pid "APP_PATH/tmp/pids/valorescarros.unicorn.pid"
stderr_path "APP_PATH/unicorn.log"
stdout_path "APP_PATH/log/unicorn.log"
listen "/tmp/APP_NAME.unicorn.sock"
worker_processes 2
timeout 30
preload_app true
before_fork do |server, worker|
if defined? ActiveRecord::Base
ActiveRecord::Base.connection.disconnect!
end
# Quit the old unicorn process
old_pid = "#{server.config[:pid]}.oldbin"
if File.exists?(old_pid) && server.pid != old_pid
begin
Process.kill("QUIT", File.read(old_pid).to_i)
rescue Errno::ENOENT, Errno::ESRCH
# someone else did our job for us
end
end
sleep 1
end
after_fork do |server, worker|
# Start up the database connection again in the worker
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
#!/bin/sh
set -e
# Example init script, this can be used with nginx, too,
# since nginx and unicorn accept the same signals
# Feel free to change any of the following variables for your app:
TIMEOUT=${TIMEOUT-60}
APP_ROOT=APP_PATH/current
PID=$APP_ROOT/tmp/pids/unicorn.pid
CMD="/usr/local/bin/unicorn -D -c $APP_ROOT/config/unicorn.rb -E production"
action="$1"
set -u
old_pid="$PID.oldbin"
cd $APP_ROOT || exit 1
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $old_pid && kill -$1 `cat $old_pid`
}
case $action in
start)
sig 0 && echo >&2 "Already running" && exit 0
$CMD
;;
stop)
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && exit 0
echo >&2 "Not running"
;;
restart|reload)
sig HUP && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
$CMD
;;
upgrade)
if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $old_pid && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $old_pid
then
echo >&2 "$old_pid still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
$CMD
;;
reopen-logs)
sig USR1
;;
*)
echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
exit 1
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment