Today we’ll be deploying a simple Sinatra app with Capistrano, using Unicorn as our web server. First things first: let’s think of a stupid name for this project. What about “sincapun”? Any objections? Good, let’s proceed.
$ bundle exec ruby sincapun.rb
[2012-03-09 16:04:17] INFO WEBrick 1.3.1
[2012-03-09 16:04:17] INFO ruby 1.9.3 (2012-02-16)[x86_64-darwin11.3.0]== Sinatra/1.3.2 has taken the stage on 4567 for development with backup from WEBrick
[2012-03-09 16:04:17] INFO WEBrick::HTTPServer#start: pid=14871 port=4567
So far, so good. Now let’s convert it to modular app and create a proper rackup file.
# config/deploy.rb# We're using RVM on a server, need this.$:.unshift(File.expand_path('./lib',ENV['rvm_path']))require'rvm/capistrano'set:rvm_ruby_string,'1.9.3'set:rvm_type,:user# Bundler tasksrequire'bundler/capistrano'set:application,"sincapun"set:repository,"git@github.com:stulentsev/sincapun.git"set:scm,:git# do not use sudoset:use_sudo,falseset(:run_method){use_sudo?:sudo::run}# This is needed to correctly handle sudo password promptdefault_run_options[:pty]=trueset:user,"myname"set:group,userset:runner,userset:host,"#{user}@myhost"# We need to be able to SSH to that box as this user.role:web,hostrole:app,hostset:rails_env,:production# Where will it be located on a server?set:deploy_to,"/srv/#{application}"set:unicorn_conf,"#{deploy_to}/current/config/unicorn.rb"set:unicorn_pid,"#{deploy_to}/shared/pids/unicorn.pid"# Unicorn control tasksnamespace:deploydotask:restartdorun"if [ -f #{unicorn_pid} ]; then kill -USR2 `cat #{unicorn_pid}`; else cd #{deploy_to}/current && bundle exec unicorn -c #{unicorn_conf} -E #{rails_env} -D; fi"endtask:startdorun"cd #{deploy_to}/current && bundle exec unicorn -c #{unicorn_conf} -E #{rails_env} -D"endtask:stopdorun"if [ -f #{unicorn_pid} ]; then kill -QUIT `cat #{unicorn_pid}`; fi"endend
We need a config file for Unicorn. Here is what it may look like:
# define paths and filenamesdeploy_to="/srv/sincapun"rails_root="#{deploy_to}/current"pid_file="#{deploy_to}/shared/pids/unicorn.pid"socket_file="#{deploy_to}/shared/unicorn.sock"log_file="#{rails_root}/log/unicorn.log"err_log="#{rails_root}/log/unicorn_error.log"old_pid=pid_file+'.oldbin'timeout30worker_processes2# increase or decreaselistensocket_file,:backlog=>1024pidpid_filestderr_patherr_logstdout_pathlog_file# make forks fasterpreload_apptrue# make sure that Bundler finds the Gemfilebefore_execdo|server|ENV['BUNDLE_GEMFILE']=File.expand_path('../Gemfile',File.dirname(__FILE__))endbefore_forkdo|server,worker|defined?(ActiveRecord::Base)andActiveRecord::Base.connection.disconnect!# zero downtime deploy magic:# if unicorn is already running, ask it to start a new process and quit.ifFile.exists?(old_pid)&&server.pid!=old_pidbeginProcess.kill("QUIT",File.read(old_pid).to_i)rescueErrno::ENOENT,Errno::ESRCH# someone else did our job for usendendendafter_forkdo|server,worker|# re-establish activerecord connections.defined?(ActiveRecord::Base)andActiveRecord::Base.establish_connectionend
That should do it. Now you can deploy your app, assuming that you have RVM on the server, you can SSH into it and write to /srv directory.
12
cap deploy:setup
cap deploy
Deploy should spit a lot of text into the console, and there should be no errors. Verify that our unicorns are launched correctly by logging into the server and running this: