Commit a8f2a0f3
Changed files (19)
config
script
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