How I Deploy Typo Using Capistrano

Posted by John Wulff Wed, 30 Apr 2008 21:03:00 GMT

I’ve been deploying all of my Rails apps with Capistrano to a MySQL, Nginx, Mongrel, God stack for a while.

I hadn’t been keeping my (this) Typo install up to date because it was such a pain to upgrade it compared to my other apps. Not anymore!

Here is my awesome Capistrano deploy task for Typo. (And my database.yml, god.config, and nginx.conf for good measure).

Any way it can be improved?

deploy.rb:
set :application,      'www.johnwulff.com'
set :typo_plugins,     [ 'delicious_sidebar', 'flickr_sidebar' ]
set :user,             'rails_admin'
set :deploy_to,        "/var/www/#{application}"
# If you change the repository be sure to flush the server's cached checkout.
set :repository,       'http://svn.typosphere.org/typo/tags/release_5_0_3'
set :typo_plugins_url, 'http://svn.typosphere.org/typo/plugins/'
# This will substantially speed things up and save typoshphere.or's bandwidth.
set :deploy_via,       :remote_cache

role :app, 'www.johnwulff.com'
role :web, 'www.johnwulff.com'
role :db,  'www.johnwulff.com', :primary => true

namespace :deploy do
  task :default do
    transaction do
      update_code
      typo_plugins.each do |plugin|
        run "cd #{current_release}; script/plugin install #{typo_plugins_url}#{plugin}"
      end
      web.disable
      symlink
      # Copy local database.yml to the new remote release.
      put File.read(File.join(File.dirname(__FILE__), 'database.yml')),
          File.join(current_release, 'config', 'database.yml')
      # Copy local nginx.conf to the new remote release.
      put File.read(File.join(File.dirname(__FILE__), 'nginx.conf')),
          File.join(current_release, 'config', 'nginx.conf')
      # Copy local god.config to the new remote release.
      put File.read(File.join(File.dirname(__FILE__), 'god.config')),
          File.join(current_release, 'config', 'god.config')
      migrate
    end
    # Stop God watches, load the fresh God config that was just uploaded, and
    # then start God watches.
    sudo "god stop #{application}"
    sudo "god load #{File.join deploy_to, 'current', 'config', 'god.config'}"
    sudo "god start #{application}"
    # Reload Nginx configuration without restarting Nginx.
    sudo "/etc/init.d/nginx reload"
    web.enable
    # Don't use sudo for cleanup.  This takes a bit longer than using sudo, but
    # it's not a good idea to give passwordless `sudo rm` permissions to
    # anyone.
    set :use_sudo, false
    cleanup
    set :use_sudo, true
  end
end
database.yml:
production:
  adapter: mysql
  database: johnwulff
  username: johnwulff
  password: *****
  host: localhost
god.config:
#!/usr/bin/env ruby
APPLICATION = 'www.johnwulff.com'
RAILS_ROOT = "/var/www/#{APPLICATION}/current"

%w{9900 9901 9902}.each do |port|
  God.watch do |w|
    pid_file = File.join RAILS_ROOT, 'tmp', 'pids', "mongrel.#{port}.pid"
    log_file = File.join RAILS_ROOT, 'log', "mongrel.#{port}.log"

    w.uid = 'rails_admin'
    w.gid = 'rails_admin'
    w.group = APPLICATION

    w.name = "#{APPLICATION}-mongrel-#{port}"
    w.interval = 30.seconds # default      

    w.start = "mongrel_rails start -d -e production -a 127.0.0.1 -c #{RAILS_ROOT} --user rails_admin --group rails_admin -p #{port} -P #{pid_file} -l #{log_file}"
    w.stop = "mongrel_rails stop -P #{pid_file}"
    w.restart = "mongrel_rails restart -P #{pid_file}"
    w.start_grace = 10.seconds
    w.restart_grace = 10.seconds
    w.pid_file = pid_file

    w.behavior(:clean_pid_file)

    w.start_if do |start|
      start.condition(:process_running) do |c|
        c.notify = 'john'
        c.interval = 5.seconds
        c.running = false
      end
    end

    w.restart_if do |restart|
      restart.condition(:memory_usage) do |c|
        c.notify = 'john'
        c.above = 150.megabytes
        c.times = [3, 5] # 3 out of 5 intervals
      end

      restart.condition(:cpu_usage) do |c|
        c.above = 50.percent
        c.times = 5
      end
    end

    # lifecycle
    w.lifecycle do |on|
      on.condition(:flapping) do |c|
        c.notify = 'john'
        c.to_state = [:start, :restart]
        c.times = 5
        c.within = 5.minute
        c.transition = :unmonitored
        c.retry_in = 10.minutes
        c.retry_times = 5
        c.retry_within = 2.hours
      end
    end
  end
end
nginx.conf:
upstream johnwulff {
  server 127.0.0.1:9900;
  server 127.0.0.1:9901;
  server 127.0.0.1:9902;
}

server {
  server_name johnwulff.com;
  rewrite ^/(.*) http://www.johnwulff.com/$1 permanent;
}

server {  
  listen  80;
  server_name  www.johnwulff.com;
  root /var/www/in_out_open/current/public;
  access_log  /var/www/www.johnwulff.com/shared/log/nginx.access.log  main;
  client_max_body_size  50M;
  # Redirect all traffic to maintenance.html if it exists.
  if (-f $document_root/system/maintenance.html){
    rewrite  ^(.*)$  /system/maintenance.html last;
    break;
  }
  location / {
    # redirect feed requests to feedburner, unless its the feedburner agent
    if ($http_user_agent !~ FeedBurner) {
      rewrite ^/articles.(rss|atom)$ http://feeds.feedburner.com/johnwulff;
      rewrite ^/xml/(atom|rss|rss20)/feed.xml$ http://feeds.feedburner.com/johnwulff;
      rewrite ^/rss$ http://feeds.feedburner.com/johnwulff;
      rewrite ^/feed/(atom|rss|rss20).xml$ http://feeds.feedburner.com/johnwulff;
    }
    # Forward header information so rails can make use of it.
    proxy_set_header  X-Real-IP  $remote_addr;
    proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect false;
    proxy_max_temp_file_size 0;
    # check for index.html for directory index
    # if its there on the filesystem then rewite 
    # the url to add /index.html to the end of it
    # and then break to send it to the next config rules.
    if (-f $request_filename/index.html) {
      rewrite (.*) $1/index.html break;
    }
    # this is the meat of the rails page caching config
    # it adds .html to the end of the url and then checks
    # the filesystem for that file. If it exists, then we
    # rewite the url to have explicit .html on the end 
    # and then send it on its way to the next config rule.
    # if there is no file on the fs then it sets all the 
    # necessary headers and proxies to our upstream mongrels
    if (-f $request_filename.html) {
      rewrite (.*) $1.html break;
    }
    if (!-f $request_filename) {
      proxy_pass http://johnwulff;
      break;
    }
  }
  error_page   500 502 503 504  /50x.html;
  location = /50x.html {
    root   html;
  }
}
Comments

Leave a comment

Comments


h %s", link_to ('scribbish', 'http://quotedprintable.com/pages/scribbish'))%>