Deploying to multiple server environments with cap
-Tuesday, April 07, 2009 By: Jon Kinney
Most anytime I develop a web application I need to deploy to multiple server environments. For me this used to mean maintaining two separate deploy.rb scripts, and I would rename one while deploying to staging, and then rename the other when I needed to deploy to production. After about three deploys I said, the hell with this! And I figured out how to allow the specification of your deployment at the command line during the cap deploy task.
Now I know what you're thinking, why not create your own cap task that is called cap deploy_production and cap deploy_staging (or whatever), but I didn't want to muck around with that. Here is how I get Capistrano to prompt ME!
1 default_run_options[:pty] = true 2 ssh_options[:forward_agent] = true 3 # also had to set up id_ras keys for the deploy user on the production box (to itself). And setup the tunnel definition as well in ~/.subversion/config 4 # Local => rs_ssh = /opt/local/bin/ssh -p 2384 -l jkinney 5 # Production => rs_ssh = /usr/bin/ssh -p 2384 -l jkinney 6 7 set :gems_for_project, %w(highline,will_paginate,etc...) # list of gems to be installed 8 9 # Make terminal prompt us for the location we want to deploy to 10 set :deploy_location, Proc.new { deploy_location = Capistrano::CLI.ui.ask "Enter deploy location (stage/prod)" } 11 12 if "#{deploy_location}" == "prod" 13 set :domain, "209.41.75.42" 14 else 15 # I have ssh setup on a non-standard port for my staging box, since it's exposed to the world. Our production box required VPN or local netowrk access. 16 ssh_options[:port] = 2384 17 set :domain, "YOUR STAGING IP HERE" 18 # note that your staging could be on the same server, just setup your application names differently then so you aren't overwriting things. 19 end 20 21 # prompts for a release tag, if that is your sort of thing... 22 set :release_tag, Proc.new { release_tag = Capistrano::CLI.ui.ask "Enter a release tag to deploy (type trunk or leave blank and hit enter to deploy from trunk)" } 23 24 role :app, domain 25 role :web, domain 26 role :db, domain, :primary => true 27 28 set :application, "jonkinneydotcom" 29 30 set :user, "deploy" 31 set :password, "secret" 32 set :deploy_to, "/var/www/apps/#{application}" 33 34 set :rails_env, "production" 35 36 # I thought this was automatic, but I seem to need to require it to cleanup my releases 37 set :keep_releases, 4 38 after "deploy", "deploy:cleanup" 39 40 # this is using subversion, I am transitioning to GIT and will post updates when I have a modified deploy.rb 41 set :repo_location, "/var/svn/your_subversion_repo" 42 set :repository, "svn+ssh://#{domain}#{repo_location}/#{application}/trunk" 43 44 namespace :deploy do 45 desc "restart passenger" 46 task :restart, :roles => :app, :except => {:no_release => true} do 47 run "touch #{current_path}/tmp/restart.txt" 48 end 49 50 [:start, :stop].each do |t| 51 desc "#{t} task is a no-op with passenger" 52 task t, :roles => :app do; end 53 end 54 55 task :after_symlink do 56 run "chmod -R a+rw #{release_path}/public" 57 58 #rcov messes with deployed apps...remove it in production 59 run "rm -rf #{release_path}/vendor/plugins/rails_rcov" 60 61 # OPTIONAL: symlink files from the FTP site's home directory to the rails_root 62 # keep them protected and use send_file to present them to the logged in user 63 # (this is more secure than hiding them in a public directory with directory listing off) 64 # run "rm -rf #{release_path}/admin_files" 65 # run "ln -s #{deploy_to}/#{shared_dir}/admin_files #{release_path}" 66 67 #symlink the files from outside the deploy path so we can keep all the uploaded images! 68 # This will allow images uploaded through an asset manager to be retained between deployments 69 run "rm -rf #{release_path}/public/assets" 70 run "ln -s #{deploy_to}/#{shared_dir}/assets #{release_path}/public/assets" 71 72 # setup database for production environment (database.yml should be ignored in svn) 73 db_params = { 74 "adapter"=>"mysql", 75 "database"=>"yourapp_production", 76 "username"=>"root", 77 "password"=>"secret", 78 "host"=>"localhost", 79 } 80 81 # OPTIONAL: Deploy to production with a sqlite3 database...because we don't need anything elaborage. 82 # And that way we can reset the db every hour or whatever with a cron job 83 # db_params = { 84 # "adapter"=>"sqlite3", 85 # "database"=>"db/production.sqlite3.db", 86 # "timeout"=>"5000" 87 # } 88 89 db_params.each do |param, default_val| 90 set "db_#{param}".to_sym, 91 #if you want to be prompted uncomment the line below this and comment out the one directly below that 92 # lambda { Capistrano::CLI.ui.ask "Enter database #{param}" do |q| q.default=default_val end} 93 param = default_val 94 end 95 96 # builds the database.yml 97 database_configuration = "production:\n" 98 db_params.each do |param, default_val| 99 val=self.send("db_#{param}") 100 database_configuration<<" #{param}: #{val}\n" 101 end 102 103 run "mkdir -p #{deploy_to}/#{shared_dir}/config" 104 105 put database_configuration, "#{deploy_to}/#{shared_dir}/config/database.yml" 106 107 #symlink the database.yml 108 run "ln -s #{deploy_to}/#{shared_dir}/config/database.yml #{deploy_to}/current/config" 109 110 #symlink the production database 111 run "ln -s #{deploy_to}/#{shared_dir}/config/production.sqlite3.db #{deploy_to}/current/db" 112 end 113 end 114 115 # This is what asks you if you're sure you want to deploy to production?!?!? 116 before "deploy:update_code", "user_confirmation_for_production_deployment" 117 task :user_confirmation_for_production_deployment, roles => :app do 118 if "#{deploy_location}" == 'prod' 119 message = "You are deploying to PRODUCTION. continue(y/n):" 120 answer = Capistrano::CLI.ui.ask(message) 121 abort "deployment to production was stopped" unless answer == 'y' 122 end 123 end 124 125 126 127 ######################Custom cap tasks that I find useful 128 desc "Configure VHost" 129 task :config_vhost do 130 vhost_config =<<-EOF 131 <VirtualHost *:80> 132 ServerName jonkinney.com 133 ServerAlias www.jonkinney.com 134 DocumentRoot #{deploy_to}/current/public 135 </VirtualHost> 136 EOF 137 put vhost_config, "#{deploy_to}/#{shared_dir}/config/vhost_config" 138 sudo "mv #{deploy_to}/#{shared_dir}/config/vhost_config /etc/apache2/sites-available/#{application}" 139 sudo "a2ensite #{application}" 140 sudo "/etc/init.d/apache2 reload" 141 end 142 143 desc "create assets directory" 144 task :create_assets_directory do 145 sudo "mkdir -p #{deploy_to}/#{shared_dir}/assets" 146 sudo "chmod -R 777 #{deploy_to}/#{shared_dir}/assets" 147 sudo "chown -R deploy:www-data #{deploy_to}/#{shared_dir}/assets" 148 end 149 150 desc "make current development database the production database" 151 task :upload_dev_db_to_prod do 152 put(File.read("db/development.sqlite3.db"), "#{deploy_to}/#{shared_dir}/config/production.sqlite3.db") 153 end 154 155 desc "run remote command" 156 task :show, :roles => :app do 157 run <<-COMMAND 158 /var/www/apps/#{application}/current/script/runner -e production 'require "pp"; pp #{command}' 159 COMMAND 160 end 161 162 desc "run remote rake db:migrate RAILS_ENV=production" 163 task :remote_db_migrate do 164 run("cd #{deploy_to}/current; /usr/bin/rake db:migrate RAILS_ENV=production") 165 end
Hopefully this has been helpful. I know Capistrano can be somewhat of a black box for people, so if you have issues with my deploy.rb or need any help feel free to contact me or post in the comments!
« Keeping passenger apps live with cron || My first full studio album finished! »
News & Events
Tech Review: Web Design For Developers - June 2009
A friend of mine in the web development community is releasing a book called "Web Design for Developers: A Programmer's Guide to Design Tools and Techniques". I was asked to do a tech review of the book and will be sharing my thoughts as well as some cool info presented in the book in a short series of upcoming blog posts. If you want to grab a beta copy of the book head over to my favorite publisher The Pragmatic Programmers.
First Class Audio Production - March 1st 2009
My most recent studio project was mixing and producing the latest a cappella album to come out of Eau Claire, WI. Until Proven Guilty is the Innocent Men's 4th studio album and marks a huge leap forward in recording and production quality for the group. Check back for demos of the mastered songs very soon! http://theinnocentmen.com.
Rate This Post: 4 (average)
Tag Cloud 
- 3 pages are tagged with General
- 2 pages are tagged with cron
- 4 pages are tagged with development
- 5 pages are tagged with rails
- 4 pages are tagged with ruby

