Busting a cap in yo' ass!

Ok, the titles lame but I hope the contents aren't. Today I'll be running through a quick Capistrano config - perfect for if your running on a VPS - that has a heap of free goodies included. Also, thanks to Skiz on #offrails for a nice start earlier after I lost some of my stuff.

Origin

One of my aim's when writing this config was to make it as standard as possible - I mean, you'd have no problems running it on say a dedicated server but there may be issues running it on say DreamHost (I'll add one for them later). Anyway, without further ado, I present the ultimate Capistrano config file of Dooooom!. Just edit your SCM Details + The App Name, setup Nginx and it's pretty much done.

Standard Features

  • Choice between Thin / Mongrel Cluster for your Application Server with automatic config file generation.

  • Choice to use sqlite3 for your production database - and to handle most aspects of deploying with it.
  • Automatically linked public/images/uploaded folder
  • Magic! (Just kidding ;))
  • Effortless deployment (seriously, it's bloody easy).

The Code

# Application Specific Details set :application, "" set :domain, "" set :deploy_via, :export set :repository, "" set :scm_username, "" set :scm_password, "" ## Magic Starts. N.B. You can set variables before if you'd like # Suitable for a vps-style system # where each part is on the same domain. # Location set :deploy_to, "/var/apps/#{application}" # Deployment details set :user, "deploy" unless exists?(:user) set :runner, user unless exists?(:runner) set :server_type, :thin unless exists?(:server_type) set :deploy_port, 9000 unless exists?(:deploy_port) set :cluster_instances, 3 unless exists?(:cluster_instances) set :use_sqlite3, true unless exists?(:use_sqlite) set :keep_releases, 3 unless exists?(:keep_releases) # Paths set :shared_database_path, "#{shared_path}/databases" set :shared_config_path, "#{shared_path}/configs" set :shared_uploaded_images_path, "#{shared_path}/uploaded_images" set :public_uploaded_images_path, "#{current_path}/public/images/uploaded" # Our helper methods def public_configuration_location_for(server = :thin) "#{current_path}/config/#{server}.yml" end def shared_configuration_location_for(server = :thin) "#{shared_config_path}/#{server}.yml" end # Our Server Roles role :app, domain.to_s role :web, domain.to_s role :db, domain.to_s, :primary => true namespace :configuration do desc "Links the local copies of the shared images folder" task :localize, :roles => :app do run "rm -rf #{public_uploaded_images_path}" # God. Damned. Reversing it removes ALL images. Not fun. run "ln -nsf #{shared_uploaded_images_path} #{public_uploaded_images_path}" end desc "Makes link for database" task :make_default_folders, :roles => :app do run "mkdir -p #{shared_config_path}" run "mkdir -p #{shared_uploaded_images_path}" end end # Application Server Choices namespace :mongrel do desc "Generate a mongrel configuration file" task :build_configuration, :roles => :app do config_options = { "user" => (runner || user), "group" => (runner || user), "log_file" => "#{current_path}/log/mongrel.log", "cwd" => current_path, "port" => deploy_port, "servers" => cluster_instances, "environment" => "production", "address" => "localhost", "pid_file" => "#{current_path}/tmp/pids/mongrel.pid" }.to_yaml put config_options, shared_configuration_location_for(:mongrel) end desc "Links the configuration file" task :link_configuration_file, :roles => :app do run "ln -nsf #{shared_configuration_location_for(:mongrel)} #{public_configuration_location_for(:mongrel)}" end desc "Setup Mongrel Cluster After Code Update" task :link_global_configuration, :roles => :app do run "ln -nsf /etc/mongrel_cluster/#{application}.yml" end %w(start stop restart).each do |action| desc "#{action} this app's Mongrel Cluster" task action.to_sym, :roles => :app do run "mongrel_rails cluster::#{action} -C #{shared_configuration_location_for(:mongrel)}" end end end namespace :thin do desc "Generate a thin configuration file" task :build_configuration, :roles => :app do config_options = { "user" => (runner || user), "group" => (runner || user), "log" => "#{current_path}/log/thin.log", "chdir" => current_path, "port" => deploy_port, "servers" => cluster_instances.to_i, "environment" => "production", "address" => "localhost", "pid" => "#{current_path}/tmp/pids/log.pid" }.to_yaml put config_options, shared_configuration_location_for(:thin) end desc "Links the configuration file" task :link_configuration_file, :roles => :app do run "ln -nsf #{shared_configuration_location_for(:thin)} #{public_configuration_location_for(:thin)}" end desc "Setup Thin Cluster After Code Update" task :link_global_configuration, :roles => :app do run "ln -nsf #{shared_configuration_location_for(:thin)} /etc/thin/#{application}.yml" end %w(start stop restart).each do |action| desc "#{action} this app's Thin Cluster" task action.to_sym, :roles => :app do run "thin #{action} -C #{shared_configuration_location_for(:thin)}" end end end # Our Database Stuff - currently only sqlite3 namespace :sqlite3 do desc "Generate a database configuration file" task :build_configuration, :roles => :db do db_options = { "adapter" => "sqlite3", "database" => "db/production.sqlite3" } config_options = {"production" => db_options}.to_yaml put config_options, "#{shared_config_path}/sqlite_config.yml" end desc "Links the configuration file" task :link_configuration_file, :roles => :db do run "ln -nsf #{shared_config_path}/sqlite_config.yml #{current_path}/config/database.yml" run "touch #{shared_database_path}/production.sqlite3" run "ln -nsf #{shared_database_path}/production.sqlite3 #{current_path}/db/production.sqlite3" end desc "Make a shared database folder" task :make_shared_folder, :roles => :db do run "mkdir -p #{shared_database_path}" end end # Our Global Web Server - NGINX :D namespace :nginx do desc "Start Nginx on the app server." task :start, :roles => :web do run "/etc/init.d/nginx start" end desc "Restart the Nginx processes on the app server by starting and stopping the cluster." task :restart , :roles => :web do run "/etc/init.d/nginx restart" end desc "Stop the Nginx processes on the app server." task :stop , :roles => :web do run "/etc/init.d/nginx stop" end desc "Stop the Nginx processes on the app server." task :reload , :roles => :web do run "/etc/init.d/nginx stop" end %w(start stop restart reload).each do |action| desc "#{action} the Nginx processes on the web server." task action.to_sym , :roles => :web do run "/etc/init.d/nginx #{action}" end end end # Our magic namespace :deploy do %w(start stop restart).each do |action| desc "#{action} our server" task action.to_sym do find_and_execute_task("#{server_type}:#{action}") end end end # After Tasks after "deploy:setup", "configuration:make_default_folders" after "deploy:setup", "#{server_type}:build_configuration" #after "#{server_type}:build_configuration", "#{server_type}:link_global_configuration" after "deploy:symlink", "configuration:localize" after "deploy:symlink", "#{server_type}:link_configuration_file" if use_sqlite3 after "deploy:setup", "sqlite3:make_shared_folder" after "deploy:setup", "sqlite3:build_configuration" after "deploy:symlink", "sqlite3:link_configuration_file" end
Posted by in Programming and it's been tagged as programming, rails, deployment, ruby as well as capistrano. There are currently 1 comments.

Comments

Thanks for the cap deployment script. It was really useful and worked with relatively little modification to work with my app.
Posted by Jack at 11:21 PM Jun 29th.

Your Comment