diff options
| -rw-r--r-- | Capfile | 3 | ||||
| -rw-r--r-- | Gemfile | 10 | ||||
| -rw-r--r-- | Gemfile.lock | 25 | ||||
| -rw-r--r-- | config/deploy.rb | 48 | ||||
| -rw-r--r-- | config/recipes/base.rb | 16 | ||||
| -rw-r--r-- | config/recipes/check.rb | 13 | ||||
| -rw-r--r-- | config/recipes/nginx.rb | 25 | ||||
| -rw-r--r-- | config/recipes/nodejs.rb | 9 | ||||
| -rw-r--r-- | config/recipes/postgresql.rb | 34 | ||||
| -rw-r--r-- | config/recipes/rvm.rb | 27 | ||||
| -rw-r--r-- | config/recipes/templates/nginx_unicorn.erb | 27 | ||||
| -rw-r--r-- | config/recipes/templates/postgresql.yml.erb | 8 | ||||
| -rw-r--r-- | config/recipes/templates/unicorn.rb.erb | 8 | ||||
| -rw-r--r-- | config/recipes/templates/unicorn_init.erb | 84 | ||||
| -rw-r--r-- | config/recipes/unicorn.rb | 26 | ||||
| -rw-r--r-- | db/schema.rb | 3 |
16 files changed, 362 insertions, 4 deletions
@@ -0,0 +1,3 @@ +load 'deploy' +load 'deploy/assets' +load 'config/deploy' @@ -34,6 +34,11 @@ group :doc do gem 'sdoc', require: false end +group :development do + gem 'capistrano' + gem 'rvm-capistrano' +end + group :development, :test do gem 'rspec-rails' gem 'rspec-fakes' @@ -50,10 +55,7 @@ end # gem 'bcrypt-ruby', '~> 3.0.0' # Use unicorn as the app server -# gem 'unicorn' - -# Use Capistrano for deployment -# gem 'capistrano', group: :development +gem 'unicorn' # Use debugger # gem 'debugger', group: [:development, :test] diff --git a/Gemfile.lock b/Gemfile.lock index e4af723..d093fa3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -30,6 +30,12 @@ GEM bootstrap-sass (2.3.2.1) sass (~> 3.2) builder (3.1.4) + capistrano (2.15.5) + highline + net-scp (>= 1.0.0) + net-sftp (>= 2.0.0) + net-ssh (>= 2.0.14) + net-ssh-gateway (>= 1.1.0) capybara (2.1.0) mime-types (>= 1.16) nokogiri (>= 1.3.3) @@ -69,6 +75,7 @@ GEM httparty multi_json (>= 1.3.4) high_voltage (1.2.4) + highline (1.6.19) hike (1.2.3) http_parser.rb (0.5.3) httparty (0.11.0) @@ -82,6 +89,7 @@ GEM railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) json (1.8.0) + kgio (2.8.0) mail (2.5.4) mime-types (~> 1.16) treetop (~> 1.4.8) @@ -90,6 +98,13 @@ GEM minitest (4.7.5) multi_json (1.7.7) multi_xml (0.5.4) + net-scp (1.1.2) + net-ssh (>= 2.6.5) + net-sftp (2.1.2) + net-ssh (>= 2.6.5) + net-ssh (2.6.8) + net-ssh-gateway (1.2.0) + net-ssh (>= 2.6.5) nokogiri (1.6.0) mini_portile (~> 0.5.0) pg (0.15.1) @@ -116,6 +131,7 @@ GEM activesupport (= 4.0.0) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) + raindrops (0.11.0) rake (10.1.0) rdoc (3.12.2) json (~> 1.4) @@ -138,6 +154,8 @@ GEM rspec-expectations (~> 2.14.0) rspec-mocks (~> 2.14.0) rubyzip (0.9.9) + rvm-capistrano (1.4.1) + capistrano (>= 2.0.0) sass (3.2.9) sass-rails (4.0.0) railties (>= 4.0.0.beta, < 5.0) @@ -180,6 +198,10 @@ GEM uglifier (2.1.2) execjs (>= 0.3.0) multi_json (~> 1.0, >= 1.0.2) + unicorn (4.6.3) + kgio (~> 2.6) + rack + raindrops (~> 0.7) websocket (1.0.7) xpath (2.0.0) nokogiri (~> 1.3) @@ -189,6 +211,7 @@ PLATFORMS DEPENDENCIES bootstrap-sass + capistrano capybara coffee-rails (~> 4.0.0) database_cleaner @@ -202,6 +225,7 @@ DEPENDENCIES rails (= 4.0.0) rspec-fakes rspec-rails + rvm-capistrano sass-rails (~> 4.0.0) sdoc selenium-webdriver @@ -209,3 +233,4 @@ DEPENDENCIES teaspoon turbolinks uglifier (>= 1.3.0) + unicorn diff --git a/config/deploy.rb b/config/deploy.rb new file mode 100644 index 0000000..7d762c2 --- /dev/null +++ b/config/deploy.rb @@ -0,0 +1,48 @@ +require "bundler/capistrano" +require "rvm/capistrano" + +load "config/recipes/base" +load "config/recipes/nginx" +load "config/recipes/unicorn" +load "config/recipes/postgresql" +load "config/recipes/nodejs" +load "config/recipes/rvm" +load "config/recipes/check" + +# Your HTTP server, Apache/etc +role :web, "www.parleytool.com" +# This may be the same as your `Web` server +role :app, "www.parleytool.com" +# This is where Rails migrations will run +role :db, "www.parleytool.com", primary: true +#role :db, "your slave db-server here" + +set :application, "parley" +set :user, "demo" +set :deploy_to, "/home/#{user}/apps/#{application}" +set :deploy_via, :remote_cache # keeps git repo on server cache +set :use_sudo, false + +set :scm, "git" +set :branch, "master" +set :repository, "git@github.com:madebyuppercut/parley.git" + +set :rvm_ruby_string, :local # use the same ruby as used locally for deployment + +default_run_options[:pty] = true # password prompt +ssh_options[:forward_agent] = true # no deploy key for github + +before 'deploy:setup', 'rvm:install_rvm' # update RVM +before 'deploy:setup', 'rvm:install_ruby' # install Ruby and create gemset (both if missing) + +after "deploy", "deploy:cleanup" # keep only the last 5 releases + +# Instructions +############## +# ssh root@198.199.101.128 +# adduser deployer --ingroup admin +# exit +# cap deploy:install +# cap deploy:setup +# cap deploy:cold +# cap nginx:start # this may be necessary if it didn't start up properly before diff --git a/config/recipes/base.rb b/config/recipes/base.rb new file mode 100644 index 0000000..d7c3714 --- /dev/null +++ b/config/recipes/base.rb @@ -0,0 +1,16 @@ +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 everything onto the server" + task :install do + run "#{sudo} apt-get -y update" + run "#{sudo} apt-get -y install python-software-properties" + end +end diff --git a/config/recipes/check.rb b/config/recipes/check.rb new file mode 100644 index 0000000..45a6e1f --- /dev/null +++ b/config/recipes/check.rb @@ -0,0 +1,13 @@ +namespace :check do + desc "Make sure local git is in sync with remote." + task :revision, roles: :web do + unless `git rev-parse HEAD` == `git rev-parse origin/#{branch}` + puts "WARNING: HEAD is not the same as origin/#{branch}" + puts "Run `git push` to sync changes." + exit + end + end + before "deploy", "check:revision" + before "deploy:migrations", "check:revision" + before "deploy:cold", "check:revision" +end diff --git a/config/recipes/nginx.rb b/config/recipes/nginx.rb new file mode 100644 index 0000000..a290800 --- /dev/null +++ b/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 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 for this application" + task :setup, roles: :web do + template "nginx_unicorn.erb", "/tmp/nginx_conf" + run "#{sudo} mv /tmp/nginx_conf /etc/nginx/sites-enabled/#{application}" + run "#{sudo} rm -f /etc/nginx/sites-enabled/default" + restart + 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 diff --git a/config/recipes/nodejs.rb b/config/recipes/nodejs.rb new file mode 100644 index 0000000..e32981b --- /dev/null +++ b/config/recipes/nodejs.rb @@ -0,0 +1,9 @@ +namespace :nodejs do + desc "Install the latest relase of Node.js" + task :install, roles: :app do + run "#{sudo} add-apt-repository 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 diff --git a/config/recipes/postgresql.rb b/config/recipes/postgresql.rb new file mode 100644 index 0000000..19d9863 --- /dev/null +++ b/config/recipes/postgresql.rb @@ -0,0 +1,34 @@ +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}_production" } + +namespace :postgresql do + desc "Install the latest stable release of PostgreSQL." + task :install, roles: :db, only: {primary: true} do + run "#{sudo} add-apt-repository 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 for this application." + 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 the database.yml configuration file." + 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 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 diff --git a/config/recipes/rvm.rb b/config/recipes/rvm.rb new file mode 100644 index 0000000..a2201e4 --- /dev/null +++ b/config/recipes/rvm.rb @@ -0,0 +1,27 @@ +set_default :ruby_version, "1.9.3-p125" +set_default :rbenv_bootstrap, "bootstrap-ubuntu-10-04" + +namespace :rbenv do + desc "Install rbenv, Ruby, and the Bundler gem" + task :install, roles: :app do + run "#{sudo} apt-get -y install curl git-core" + run "curl -L https://raw.github.com/fesplugas/rbenv-installer/master/bin/rbenv-installer | bash" + bashrc = <<-BASHRC +if [ -d $HOME/.rbenv ]; then + export PATH="$HOME/.rbenv/bin:$PATH" + eval "$(rbenv init -)" +fi +BASHRC + put bashrc, "/tmp/rbenvrc" + run "cat /tmp/rbenvrc ~/.bashrc > ~/.bashrc.tmp" + run "mv ~/.bashrc.tmp ~/.bashrc" + run %q{export PATH="$HOME/.rbenv/bin:$PATH"} + run %q{eval "$(rbenv init -)"} + run "rbenv #{rbenv_bootstrap}" + run "rbenv install #{ruby_version}" + run "rbenv global #{ruby_version}" + run "gem install bundler --no-ri --no-rdoc" + run "rbenv rehash" + end + after "deploy:install", "rbenv:install" +end diff --git a/config/recipes/templates/nginx_unicorn.erb b/config/recipes/templates/nginx_unicorn.erb new file mode 100644 index 0000000..48e44b1 --- /dev/null +++ b/config/recipes/templates/nginx_unicorn.erb @@ -0,0 +1,27 @@ +upstream unicorn { + server unix:/tmp/unicorn.<%= application %>.sock fail_timeout=0; +} + +server { + listen 80 default deferred; + # server_name example.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; +} diff --git a/config/recipes/templates/postgresql.yml.erb b/config/recipes/templates/postgresql.yml.erb new file mode 100644 index 0000000..61809be --- /dev/null +++ b/config/recipes/templates/postgresql.yml.erb @@ -0,0 +1,8 @@ +production: + adapter: postgresql + encoding: unicode + database: <%= postgresql_database %> + pool: 5 + username: <%= postgresql_user %> + password: <%= postgresql_password %> + host: <%= postgresql_host %> diff --git a/config/recipes/templates/unicorn.rb.erb b/config/recipes/templates/unicorn.rb.erb new file mode 100644 index 0000000..1f51905 --- /dev/null +++ b/config/recipes/templates/unicorn.rb.erb @@ -0,0 +1,8 @@ +working_directory "<%= current_path %>" +pid "<%= unicorn_pid %>" +stderr_path "<%= unicorn_log %>" +stdout_path "<%= unicorn_log %>" + +listen "/tmp/unicorn.<%= application %>.sock" +worker_processes <%= unicorn_workers %> +timeout 30 diff --git a/config/recipes/templates/unicorn_init.erb b/config/recipes/templates/unicorn_init.erb new file mode 100644 index 0000000..cc78278 --- /dev/null +++ b/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 -D -c <%= unicorn_config %> -E production" +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 HUP && 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 diff --git a/config/recipes/unicorn.rb b/config/recipes/unicorn.rb new file mode 100644 index 0000000..a5cbe1b --- /dev/null +++ b/config/recipes/unicorn.rb @@ -0,0 +1,26 @@ +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.log" } +set_default(:unicorn_workers, 2) + +namespace :unicorn do + desc "Setup Unicorn initializer and app configuration" + task :setup, roles: :app do + run "mkdir -p #{shared_path}/config" + 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 diff --git a/db/schema.rb b/db/schema.rb index 19cb362..56feeb7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -13,6 +13,9 @@ ActiveRecord::Schema.define(version: 20130719165834) do + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + create_table "sign_ups", force: true do |t| t.string "email" t.datetime "created_at" |
