Skip to content

Instantly share code, notes, and snippets.

@thbar
Created November 12, 2012 20:15
Show Gist options
  • Save thbar/4061603 to your computer and use it in GitHub Desktop.
Save thbar/4061603 to your computer and use it in GitHub Desktop.
RubyOnRails DotCloud Rails setup

Description of current setup

Initially, I was using only postinstall to do migrations and assets precompilation.

At some point though, since the precompilation is super slow, I had time outs when pushing.

Based on advice by Andy (I think), I moved stuff to postbuild.

Faced to the need of running migrations, I decided to attempt detecting instance 0 to only run those on one machine (and it worked fine).

Similarly, I deployed the cron jobs only on one instance.

For cron I had to hardcode the path to rvm wrappers.

For database connection: Rails evaluates database.yml via ERB, so I built a little dot_cloud.rb configuration helper to grab the data from the environment file.

Things would have been definitely easier here if the variables had been exposed as real environment variables.

Post deploy, I launch ab to make sure all the passenger are immediately fired up and avoid delays for the end-user.

Things to improve for the advanced user:

  • I'd like to go even further and hope to use the latest "live" deploy protocol to have absolutely zero downtime if I can (tips welcome!)
  • assets precompilation is very, very slow on instances (much faster locally, but it's much more convenient to not have to check the files in git) - anything to fasten that will be welcome (replacing therubyracer by something else etc... unsure)
MAILTO="[email protected]"
PATH=/usr/local/rvm/wrappers/ruby-1.9.2-p136@dotcloud:/usr/local/rvm/gems/ruby-1.9.2-p136@dotcloud/bin:/usr/local/rvm/gems/ruby-1.9.2-p136@global/bin:/usr/local/rvm/rubies/ruby-1.9.2-p136/bin:/usr/local/rvm/bin:/usr/local/bin:/usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/lib/jvm/java-6-sun/bin
GEM_HOME=/usr/local/rvm/gems/ruby-1.9.2-p136@dotcloud
RAILS_ENV=production
0 1 * * * cd ~/current && rake your_task
<%
require 'dot_cloud'
database = DotCloud.staging? ? 'myappstaging' : 'myapp'
yaml = DotCloud.config
%>
production:
adapter: postgresql
encoding: unicode
database: <%= database %>
username: <%= database %>
password: <%= yaml['MYAPP_DB_SQL_PASSWORD'] %>
pool: 5
host: <%= yaml['DOTCLOUD_DB_SQL_HOST'] %>
port: <%= yaml['DOTCLOUD_DB_SQL_PORT'] %>
#!/bin/sh
set -e
echo Backing up...
./backup
echo Deploying...
dotcloud push --application myapp --git
echo Waking up!!! (make sure all passenger instances are touched)
ab -n 10 -c 3 https://www.myapp.com/
require 'yaml'
module DotCloud
def self.config
@yaml ||= YAML.load(IO.read('/home/dotcloud/environment.yml'))
end
def self.staging?
case config['DOTCLOUD_PROJECT']
when 'myappstaging'; true
when 'myapp'; false
else raise "Unsupported dotcloud app"
end
end
# examples of setters
def self.smtp_username
config['MYAPP_SMTP_USERNAME']
end
def self.smtp_password
config['MYAPP_SMTP_PASSWORD']
end
end
www:
type: ruby
config:
ruby-version: 1.9.2
exclude_bundler_groups:
- development
- test
postbuild: ./postbuild
db:
xxx:
source 'http://rubygems.org'
gem 'rails', '3.2.x'
# Gems used only for assets and not required
# in production environments by default.
group :assets do
gem 'sass-rails', "3.2.5"
gem 'coffee-rails', "3.2.2"
gem 'uglifier', '1.2.4'
gem 'twitter-bootstrap-rails'
end
# ...
group :dotcloud do
# DotCloud does not provide a js runtime today - add one
gem 'therubyracer'
end
#!/bin/sh
set -e
echo ====== postbuild starting =======
echo Currently in folder `pwd`
cp config/database.dotcloud.yml config/database.yml
echo ====== precompiling assets ===========
rake assets:precompile RAILS_ENV=production
echo ====== postbuild done =========
#!/bin/sh
set -e
echo ===== postinstall starting =====
service_id=$(ruby -e "require 'json'; env = JSON.parse(File.read('/home/dotcloud/environment.json')); puts env['DOTCLOUD_SERVICE_ID']")
if [ "$service_id" = "0" ]
then
echo ====== migrating db + installing crontab ==========
# TODO - allow to pass a variable to only run migrate if necessary to speed things up
# rake db:migrate cron:verify cron:install RAILS_ENV=production
rake cron:verify cron:install RAILS_ENV=production
fi
echo ====== postinstall done! =======
def system!(cmd)
raise "Cannot run command!!!" unless system(cmd)
end
namespace :cron do
desc "Verify ruby version expected by cron jobs"
task :verify => :environment do
# safeguard since I hardcoded the ruby path in crontab
raise "Ruby version changed!" unless `ruby -v` =~ /ruby 1.9.2p136/
end
desc "Install the cron jobs (except on staging)"
task :install => :environment do
if DotCloud.staging?
# avoid sending emails in staging etc
puts "Cron jobs not installed - staging server"
else
system!("crontab #{Rails.root.join('config', 'crontab')}")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment