Commit a8f2a0f3

mo khan <mo@mokhan.ca>
2013-07-27 15:01:54
attempt to use rvm with capistrano
1 parent ebdd6eb
config/recipes/templates/monit/nginx.erb
@@ -0,0 +1,5 @@
+check process nginx with pidfile /var/run/nginx.pid
+  start program = "/etc/init.d/nginx start"
+  stop program = "/etc/init.d/nginx stop"
+  if children > 250 then restart
+  if 5 restarts within 5 cycles then timeout
config/recipes/templates/monit/postgresql.erb
@@ -0,0 +1,5 @@
+check process postgresql with pidfile <%= postgresql_pid %>
+  start program = "/etc/init.d/postgresql start"
+  stop program = "/etc/init.d/postgresql stop"
+  if failed host localhost port 5432 protocol pgsql then restart
+  if 5 restarts within 5 cycles then timeout
config/recipes/templates/monit/unicorn.erb
@@ -0,0 +1,15 @@
+check process <%= application %>_unicorn with pidfile <%= unicorn_pid %>
+  start program = "/etc/init.d/unicorn_<%= application %> start"
+  stop program = "/etc/init.d/unicorn_<%= application %> stop"
+
+<% unicorn_workers.times do |n| %>
+  <% pid = unicorn_pid.sub(".pid", ".#{n}.pid") %>
+  check process <%= application %>_unicorn_worker_<%= n %> with pidfile <%= pid %>
+    start program = "/bin/true"
+    stop program = "/usr/bin/test -s <%= pid %> && /bin/kill -QUIT `cat <%= pid  %>`"
+    if mem > 200.0 MB for 1 cycle then restart
+    if cpu > 50% for 3 cycles then restart
+    if 5 restarts within 5 cycles then timeout
+    alert mo@mokhan.ca only on { pid }
+    if changed pid 2 times within 60 cycles then alert
+<% end %>
config/recipes/templates/nginx_unicorn.erb
@@ -0,0 +1,27 @@
+upstream unicorn {
+  server unix:<%= shared_path %>/sockets/unicorn.sock fail_timeout=0;
+}
+
+server {
+  listen 80 default deferred;
+  # server_name cakeside.com
+  root <%= current_path %>/public;
+
+  location ^~ /assets/ {
+    gzip_static on;
+    expires max;
+    add_header Cache-Control public;
+  }
+
+  try_files $uri/index.html $uri @unicorn;
+  location @unicorn {
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header HOST $http_host;
+    proxy_redirect off;
+    proxy_pass http://unicorn;
+  }
+
+  error_page 500 502 503 504 /500.html;
+  client_max_body_size 4G;
+  keepalive_timeout 10;
+}
config/recipes/templates/postgresql.yml.erb
@@ -0,0 +1,8 @@
+<%= rails_env %>:
+  adapter: postgresql
+  encoding: unicode
+  database: <%= postgresql_database %>
+  pool: 5
+  username: <%= postgresql_user %>
+  password: <%= postgresql_password %>
+  host: <%= postgresql_host %>
config/recipes/templates/unicorn.rb.erb
@@ -0,0 +1,33 @@
+working_directory "<%= current_path %>"
+pid "<%= unicorn_pid %>"
+stderr_path "<%= unicorn_log %>"
+stdout_path "<%= unicorn_log %>"
+
+listen "<%= shared_path %>/sockets/unicorn.sock"
+worker_processes <%= unicorn_workers %>
+timeout 30
+
+preload_app true
+
+before_fork do |server, worker|
+  if defined? ActiveRecord::Base
+    ActiveRecord::Base.connection.disconnect!
+  end
+
+  old_pid = "#{server.config[:pid]}.oldbin"
+  if File.exists?(old_pid) && server.pid != old_pid
+    begin
+      Process.kill("QUIT", File.read(old_pid).to_i)
+    rescue Errno::ENOENT, Errno::ESRCH
+      # someone else killed it
+    end
+  end
+end
+
+after_fork do |server, worker|
+  if defined? ActiveRecord::Base
+    ActiveRecord::Base.establish_connection
+  end
+  child_pid = server.config[:pid].sub(".pid", ".#{worker.nr}.pid")
+  system("echo #{Process.pid} > #{child_pid}")
+end
config/recipes/templates/unicorn_init.erb
@@ -0,0 +1,84 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:          unicorn
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Manage unicorn server
+# Description:       Start, stop, restart unicorn server for a specific application.
+### END INIT INFO
+set -e
+
+# Feel free to change any of the following variables for your app:
+TIMEOUT=${TIMEOUT-60}
+APP_ROOT=<%= current_path %>
+PID=<%= unicorn_pid %>
+CMD="cd <%= current_path %>; bundle exec unicorn -E <%= rails_env %> -D -c <%= unicorn_config %>"
+AS_USER=<%= unicorn_user %>
+set -u
+
+OLD_PIN="$PID.oldbin"
+
+sig () {
+  test -s "$PID" && kill -$1 `cat $PID`
+}
+
+oldsig () {
+  test -s $OLD_PIN && kill -$1 `cat $OLD_PIN`
+}
+
+run () {
+  if [ "$(id -un)" = "$AS_USER" ]; then
+    eval $1
+  else
+    su -c "$1" - $AS_USER
+  fi
+}
+
+case "$1" in
+start)
+  sig 0 && echo >&2 "Already running" && exit 0
+  run "$CMD"
+  ;;
+stop)
+  sig QUIT && exit 0
+  echo >&2 "Not running"
+  ;;
+force-stop)
+  sig TERM && exit 0
+  echo >&2 "Not running"
+  ;;
+restart|reload)
+  sig USR2 && echo reloaded OK && exit 0
+  echo >&2 "Couldn't reload, starting '$CMD' instead"
+  run "$CMD"
+  ;;
+upgrade)
+  if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
+  then
+    n=$TIMEOUT
+    while test -s $OLD_PIN && test $n -ge 0
+    do
+      printf '.' && sleep 1 && n=$(( $n - 1 ))
+    done
+    echo
+
+    if test $n -lt 0 && test -s $OLD_PIN
+    then
+      echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds"
+      exit 1
+    fi
+    exit 0
+  fi
+  echo >&2 "Couldn't upgrade, starting '$CMD' instead"
+  run "$CMD"
+  ;;
+reopen-logs)
+  sig USR1
+  ;;
+*)
+  echo >&2 "Usage: $0 <start|stop|restart|upgrade|force-stop|reopen-logs>"
+  exit 1
+  ;;
+esac
config/recipes/base.rb
@@ -0,0 +1,27 @@
+def template(from, to)
+  erb = File.read(File.expand_path("../templates/#{from}", __FILE__))
+  put ERB.new(erb).result(binding), to
+end
+
+def set_default(name, *args, &block)
+  set(name, *args, &block) unless exists?(name)
+end
+
+namespace :deploy do
+  desc "install all the things"
+  task :install do
+    run "#{sudo} apt-get -y update", :shell => :bash
+    run "#{sudo} apt-get -y install curl git-core python-software-properties imagemagick libmagickwand-dev memcached", :shell => :bash
+    run "#{sudo} apt-get -y install build-essential", :shell => :bash
+    # Packages required for compilation of some stdlib modules
+    run "#{sudo} apt-get -y install tklib", :shell => :bash
+    # Extras for RubyGems and Rails:
+    run "#{sudo} apt-get -y install zlib1g-dev libssl-dev", :shell => :bash
+    # Readline Dev on Ubuntu 12.04 LTS:
+    run "#{sudo} apt-get -y install libreadline-gplv2-dev", :shell => :bash
+    # Install some nokogiri dependencies:
+    run "#{sudo} apt-get -y install libxml2 libxml2-dev libxslt1-dev", :shell => :bash
+    run "#{sudo} apt-get -y install gawk libreadline6-dev libyaml-dev libsqlite3-dev sqlite3 autoconf libgdbm-dev libncurses5-dev automake libtool bison pkg-config libffi-dev", :shell => :bash
+    run "#{sudo} apt-get -y autoremove", :shell => :bash
+  end
+end
config/recipes/delayed_job.rb
@@ -0,0 +1,19 @@
+namespace :delayed_job do 
+  desc "start the delayed_job process"
+  task :start, :roles => :app do
+    run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job start"
+  end
+  after "deploy:start", "delayed_job:start"
+
+  desc "stop the delayed_job process"
+  task :stop, :roles => :app do
+    run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job stop"
+  end
+  after "deploy:stop", "delayed_job:stop"
+
+  desc "Restart the delayed_job process"
+  task :restart, :roles => :app do
+    run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job restart"
+  end
+  after "deploy:restart", "delayed_job:restart"
+end
config/recipes/environments.rb
@@ -0,0 +1,4 @@
+set :stages, %w(production staging)
+set :default_stage, "staging"
+require 'capistrano/ext/multistage'
+#require 'capistrano/gitflow'
config/recipes/monit.rb
@@ -0,0 +1,37 @@
+namespace :monit do
+  desc "install monit"
+  task :install do
+    run "#{sudo} apt-get -y install monit"
+  end
+  after "deploy:install", "monit:install"
+
+  desc "setup monit config"
+  task :setup do
+    monit_config "monitrc", "/etc/monit/monitrc"
+    nginx
+    postgresql
+    unicorn
+    syntax
+    reload
+  end
+  after "deploy:setup", "monit:setup"
+
+  task(:nginx, roles: :web) { monit_config "nginx" }
+  task(:postgresql, roles: :db) { monit_config "postgresql" }
+  task(:unicorn, roles: :app) { monit_config "unicorn" }
+
+  %w[start stop restart syntax reload].each do |command|
+    desc "run monit #{command} script"
+    task command do
+      run "#{sudo} service monit #{command}"
+    end
+  end
+end
+
+def monit_config(name, destination = nil)
+  destination ||= "/etc/monit/conf.d/#{name}.conf"
+  template "monit/#{name}.erb", "/tmp/monit_#{name}"
+  run "#{sudo} mv /tmp/monit_#{name} #{destination}"
+  run "#{sudo} chown root #{destination}"
+  run "#{sudo} chmod 600 #{destination}"
+end
config/recipes/nginx.rb
@@ -0,0 +1,25 @@
+namespace :nginx do
+  desc "Install latest stable release of nginx"
+  task :install, roles: :web do
+    run "#{sudo} add-apt-repository -y ppa:nginx/stable"
+    run "#{sudo} apt-get -y update"
+    run "#{sudo} apt-get -y install nginx"
+  end
+  after "deploy:install", "nginx:install"
+
+  desc "setup nginx configuration"
+  task :setup, roles: :web do
+    template "nginx_unicorn.erb", "/tmp/nginx_conf"
+    run "#{sudo} mv /tmp/nginx_conf /etc/nginx/sites-available/#{application}"
+    run "#{sudo} ln -s /etc/nginx/sites-available/#{application} /etc/nginx/sites-enabled/#{application}"
+    run "#{sudo} rm -f /etc/nginx/sites-enabled/default"
+  end
+  after "deploy:setup", "nginx:setup"
+
+  %w[start stop restart].each do |command|
+    desc "#{command} nginx"
+    task command, roles: :web do
+      run "#{sudo} service nginx #{command}"
+    end
+  end
+end
config/recipes/nodejs.rb
@@ -0,0 +1,9 @@
+namespace :nodejs do
+  desc "install node.js"
+  task :install, roles: :app do
+    run "#{sudo} add-apt-repository -y ppa:chris-lea/node.js"
+    run "#{sudo} apt-get -y update"
+    run "#{sudo} apt-get -y install nodejs"
+  end
+  after "deploy:install", "nodejs:install"
+end
config/recipes/postgresql.rb
@@ -0,0 +1,46 @@
+set_default(:postgresql_host, "localhost")
+set_default(:postgresql_user) { application }
+set_default(:postgresql_password) { Capistrano::CLI.password_prompt "PostgreSQL Password: " }
+set_default(:postgresql_database) { "#{application}_#{rails_env}" }
+set_default(:postgresql_pid) { "/var/run/postgresql/9.1-main.pid" }
+
+namespace :postgresql do
+  desc "install the latest release or postgresql"
+  task :install, roles: :db, only: { primary: true } do
+    run "#{sudo} add-apt-repository -y ppa:pitti/postgresql"
+    run "#{sudo} apt-get -y update"
+    run "#{sudo} apt-get -y install postgresql libpq-dev"
+  end
+  after "deploy:install", "postgresql:install"
+
+  desc "create a database"
+  task :create_database, roles: :db, only: { primary: true } do
+    run %Q{#{sudo} -u postgres psql -c "create user #{postgresql_user} with password '#{postgresql_password}';"}
+    run %Q{#{sudo} -u postgres psql -c "create database #{postgresql_database} owner #{postgresql_user};"}
+  end
+  after "deploy:setup", "postgresql:create_database"
+
+  desc "generate database.yml"
+  task :setup, roles: :app do
+    run "mkdir -p #{shared_path}/config"
+    template "postgresql.yml.erb", "#{shared_path}/config/database.yml"
+  end
+  after "deploy:setup", "postgresql:setup"
+
+  desc "symlink the database.yml file into the latest release"
+  task :symlink, roles: :app do
+    run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml"
+  end
+  after "deploy:finalize_update", "postgresql:symlink"
+end
+
+#namespace :deploy do
+  #task :symlink_db, :roles => :app do
+    #run "chmod +x #{release_path}/script/restart_delayed_job"
+    #run "ln -nfs #{release_path}/config/database.production.yml.example #{release_path}/config/database.yml"
+  #end
+  #task :restart, :roles => :web do
+    #run "touch #{current_path}/tmp/restart.txt"
+  #end
+#end
+#after 'deploy:update_code', 'deploy:symlink_db'
config/recipes/rvm.rb
@@ -0,0 +1,9 @@
+require "rvm/capistrano"
+require 'bundler/capistrano'
+set :rvm_ruby_string, :local
+set :rvm_autolibs_flag, :enable
+set :rvm_type, :user
+set :default_shell, :bash
+
+after "deploy:install", "rvm:install_rvm"
+after "deploy:install", "rvm:install_ruby"
config/recipes/unicorn.rb
@@ -0,0 +1,27 @@
+set_default(:unicorn_user) { user }
+set_default(:unicorn_pid) { "#{current_path}/tmp/pids/unicorn.pid" }
+set_default(:unicorn_config) { "#{shared_path}/config/unicorn.rb" }
+set_default(:unicorn_log) { "#{shared_path}/log/unicorn.rb" }
+set_default(:unicorn_workers, 4)
+
+namespace :unicorn do
+  desc "setup unicorn"
+  task :setup, roles: :app do
+    run "mkdir -p #{shared_path}/config"
+    run "mkdir -p #{shared_path}/sockets"
+    template "unicorn.rb.erb", unicorn_config
+    template "unicorn_init.erb", "/tmp/unicorn_init"
+    run "chmod +x /tmp/unicorn_init"
+    run "#{sudo} mv /tmp/unicorn_init /etc/init.d/unicorn_#{application}"
+    run "#{sudo} update-rc.d -f unicorn_#{application} defaults"
+  end
+  after "deploy:setup", "unicorn:setup"
+
+  %w[start stop restart].each do |command|
+    desc "#{command} unicorn"
+    task command, roles: :app do
+      run "service unicorn_#{application} #{command}"
+    end
+    after "deploy:#{command}", "unicorn:#{command}"
+  end
+end
config/deploy.rb
@@ -1,58 +1,36 @@
-require "rvm/capistrano"
-set :rvm_ruby_string, 'ruby-2.0.0-p247@cakeside'
-set :rvm_type, :system
-require 'bundler/capistrano'                 # loads RVM's capistrano plugin
-set :stages, %w(production staging)
-set :default_stage, "staging"
-require 'capistrano/ext/multistage'
-require 'capistrano/gitflow'
-set :application, "www.cakeside.com"
-set :deploy_via, :remote_cache
-set :user, "cakeside"
-set :group, "rvm"
+load "config/recipes/rvm"
+load "config/recipes/environments"
+load "config/recipes/base"
+load "config/recipes/nginx"
+load "config/recipes/unicorn"
+load "config/recipes/postgresql"
+load "config/recipes/nodejs"
+load "config/recipes/monit"
+
+set :application, "cakeside"
+set :user, "deployer"
+#set :group, "rvm"
 set :use_sudo, false
-set :deploy_to, "/home/cakeside/apps/#{application}"
+default_run_options[:pty] = true # password prompt
 
+# git
 set :scm, :git
+set :scm_verbose, true
 set :repository,  "git@bitbucket.org:mocheen/cakeside.git"
-set :keep_releases, 3
 set :branch, "master"
-set :deploy_env, 'production'
-set :scm_verbose, true
+set :deploy_via, :remote_cache
+
+#copy
+#set :scm, :none
+#set :repository, "."
+#set :deploy_via, :copy
+
+set :deploy_to, "/home/#{user}/apps/#{application}"
+set :keep_releases, 3
 set :normalize_asset_timestamps, false
 set :ssh_options, {:forward_agent => true}
 
-after "deploy:setup", "rvm:install_rvm"
-before "deploy", "rvm:install_ruby"
 after "deploy", "deploy:cleanup" # remove old releases
-after 'deploy:update_code', 'deploy:symlink_db'
-after "deploy:start", "delayed_job:start"
-after "deploy:stop", "delayed_job:stop"
-after "deploy:restart", "delayed_job:restart"
-
-namespace :deploy do
-  task :symlink_db, :roles => :app do
-    run "chmod +x #{release_path}/script/restart_delayed_job"
-    run "ln -nfs #{release_path}/config/database.production.yml.example #{release_path}/config/database.yml"
-  end
-  task :restart, :roles => :web do
-    run "touch #{current_path}/tmp/restart.txt"
-  end
-end
-namespace :delayed_job do 
-  desc "start the delayed_job process"
-  task :start, :roles => :app do
-    run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job start"
-  end
-  desc "stop the delayed_job process"
-  task :stop, :roles => :app do
-    run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job stop"
-  end
-  desc "Restart the delayed_job process"
-  task :restart, :roles => :app do
-    run "cd #{current_path}; RAILS_ENV=#{rails_env} script/delayed_job restart"
-  end
-end
 
-        require './config/boot'
-        require 'airbrake/capistrano'
+require './config/boot'
+require 'airbrake/capistrano'
script/features
@@ -1,5 +0,0 @@
-#!/bin/bash
-
-set -e 
-
-cucumber -drb $*
capfile
@@ -1,5 +1,5 @@
 load 'deploy'
-load 'deploy/assets'
+#load 'deploy/assets'
 load 'config/deploy' # remove this line to skip loading any of the default tasks
 
 task :search_libs, :roles => :web do