Ubuntu+Nginx+Unicorn+Rails+Capistrano+Resque+God — Gist
この記事から設定を例として抽出
定義更新する
- God はシステム(のrbenv)とかで入れてる前提なので、そうじゃない場合は適宜変更する。
Ubuntu+Nginx+Unicorn+Rails+Capistrano+Resque+God — Gist
この記事から設定を例として抽出
定義更新する
| # This file is used by Rack-based servers to start the application. | |
| require ::File.expand_path('../config/environment', __FILE__) | |
| require 'unicorn/oob_gc' | |
| use Unicorn::OobGC, 5 | |
| run AppName::Application |
| # -*- coding: utf-8 -*- | |
| # deploy 時に自動で bundle install | |
| require 'bundler/capistrano' | |
| # deploy 時に自動で rake assets:precompile | |
| load 'deploy/assets' | |
| default_run_options[:pty] = true | |
| # アプリケーションの設定 | |
| set :application, 'app' # Change! | |
| set :domain, 'app.com' # Change! | |
| set :rails_env, 'production' | |
| set :user, 'deployer' # Change! | |
| set :runner, 'deployer' # Change! | |
| set :repository, "[email protected]" # Change! | |
| set :scm, :git | |
| set :bundle_gemfile, "Gemfile" | |
| set :bundle_flags, "--quiet" | |
| set :deploy_via, :copy | |
| set :deploy_to, "/home/#{user}/#{application}" | |
| set :use_sudo, false | |
| server domain, :app, :web | |
| set :god_dir, '/etc/god' | |
| set(:god_cmd) { "#{sudo} /usr/local/rbenv/shims/god" } | |
| set(:local_unicorn_god_name) { "unicorn-#{rails_env}.god" } | |
| set(:local_resque_god_name) { "resque-#{rails_env}.god" } | |
| set(:local_resque_scheduler_god_name) {"resque-scheduler-#{rails_env}.god" } | |
| set(:unicorn_god_name) { "#{application}-unicorn-#{rails_env}.god" } | |
| set(:resque_god_name) { "#{application}-resque-#{rails_env}.god" } | |
| set(:resque_scheduler_god_name) { "#{application}-resque-scheduler-#{rails_env}.god" } | |
| # 再起動後に古い releases を cleanup | |
| after "deploy:restart", 'deploy:cleanup', "unicorn:update_config", "resque:update_config", "god:reload_resque", "god:reload_unicorn" | |
| after "deploy:setup", "db:create", "unicorn:setup", "resque:setup" | |
| after "deploy", "deploy:migrate" | |
| namespace :unicorn do | |
| task :setup do | |
| upload("config/#{local_unicorn_god_name}", "/tmp/#{unicorn_god_name}") | |
| run "#{sudo} mv /tmp/#{unicorn_god_name} /etc/god/#{unicorn_god_name}" | |
| end | |
| task :update_config do | |
| run "cd #{current_path} && #{sudo} cp config/#{local_unicorn_god_name} #{File.join(god_dir, unicorn_god_name)}" | |
| end | |
| end | |
| namespace :resque do | |
| task :setup do | |
| upload("config/#{local_resque_god_name}", "/tmp/#{resque_god_name}") | |
| run "#{sudo} mv /tmp/#{resque_god_name} /etc/god/#{resque_god_name}" | |
| upload("config/#{local_resque_scheduler_god_name}", "/tmp/#{resque_scheduler_god_name}") | |
| run "#{sudo} mv /tmp/#{resque_scheduler_god_name} /etc/god/#{resque_scheduler_god_name}" | |
| end | |
| task :update_config do | |
| run "cd #{current_path} && #{sudo} cp config/#{local_resque_god_name} #{File.join(god_dir, resque_god_name)}" | |
| run "cd #{current_path} && #{sudo} cp config/#{local_resque_scheduler_god_name} #{File.join(god_dir, resque_scheduler_god_name)}" | |
| end | |
| end | |
| namespace :god do | |
| desc "Hot-reload God configuration for the Resque worker" | |
| task :restart_resque do | |
| run "#{god} stop resque" | |
| run "#{god} load #{File.join(god_dir, resque_god_name)}" | |
| run "#{god} start resque" | |
| run "#{god} stop resque-scheduler" | |
| run "#{god} load #{File.join(god_dir, resque_scheduler_god_name)}" | |
| run "#{god} start resque-scheduler" | |
| end | |
| task :reload_resque do | |
| run "#{god} restart resque" | |
| run "#{god} restart resque-scheduler" | |
| end | |
| desc "Hot-reload God configuration for the Unicorn" | |
| task :reload_unicorn do | |
| run "#{god} restart unicorn" | |
| end | |
| desc "Restart God configuration for the Unicorn" | |
| task :restart_unicorn do | |
| run "#{god} stop unicorn" | |
| run "#{god} load #{File.join(god_dir, unicorn_god_name)}" | |
| run "#{god} start unicorn" | |
| end | |
| end |
| # capistrano-nginxでデプロイするのでERB | |
| upstream <%= application %> { | |
| server unix:/tmp/<%= application %>-unicorn.sock fail_timeout=30s max_fails=3; | |
| } | |
| server { | |
| listen 80; | |
| server_name app.com; # Change! | |
| root /home/<%= user %>/<%= application %>/current/public; | |
| access_log /var/log/nginx/<%= application %>.access.log; | |
| error_log /var/log/nginx/<%= application %>.error.log; | |
| location / { | |
| 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_pass http://unicorn.app.com; | |
| } | |
| location = /favicon.ico { | |
| gzip_static on; | |
| # http://wiki.nginx.org/HttpGzipModule#gzip_vary | |
| gzip_vary on; | |
| expires max; | |
| add_header Cache-Control public; | |
| } | |
| location = /robots.txt { | |
| } | |
| location ~ ^/(assets|images|javascripts|stylesheets|system)/ { | |
| gzip_static on; | |
| # http://wiki.nginx.org/HttpGzipModule#gzip_vary | |
| gzip_vary on; | |
| expires max; | |
| add_header Cache-Control public; | |
| } | |
| } |
| # In config/resque-production.god | |
| God.watch do |w| | |
| w.name = 'resque' | |
| w.interval = 30.seconds | |
| w.env = { 'RAILS_ENV' => 'production', 'QUEUE' => '*' } | |
| w.uid = 'DEPLOYER' # Change! | |
| w.gid = 'GROUP' # Change! | |
| w.dir = '/home/DEPLOYER/APPNEME/current' # Change! | |
| w.start = "bundle exec rake resque:work" | |
| w.start_grace = 10.seconds | |
| w.log = '/home/DEPLOYER/APPNAME/current/log/resque-worker.log' # Change! | |
| # restart if memory gets too high | |
| w.transition(:up, :restart) do |on| | |
| on.condition(:memory_usage) do |c| | |
| c.above = 100.megabytes | |
| c.times = 2 | |
| end | |
| end | |
| # determine the state on startup | |
| w.transition(:init, { true => :up, false => :start }) do |on| | |
| on.condition(:process_running) do |c| | |
| c.running = true | |
| end | |
| end | |
| # determine when process has finished starting | |
| w.transition([:start, :restart], :up) do |on| | |
| on.condition(:process_running) do |c| | |
| c.running = true | |
| c.interval = 5.seconds | |
| end | |
| # failsafe | |
| on.condition(:tries) do |c| | |
| c.times = 5 | |
| c.transition = :start | |
| c.interval = 5.seconds | |
| end | |
| end | |
| # start if process is not running | |
| w.transition(:up, :start) do |on| | |
| on.condition(:process_running) do |c| | |
| c.running = false | |
| end | |
| end | |
| end | |
| # vim: set filetype=ruby: |
| # In config/resque-scheduler-production.god | |
| God.watch do |w| | |
| w.name = 'resque-scheduler' | |
| w.interval = 30.seconds | |
| w.env = { 'RAILS_ENV' => 'production', 'QUEUE' => '*' } | |
| w.uid = 'DEPLOYER' # Change! | |
| w.gid = 'GROUP' # Change! | |
| w.dir = '/home/DEPLOYER/APPNEME/current' # Change! | |
| w.start = "bundle exec rake resque:scheduler" | |
| w.start_grace = 10.seconds | |
| w.log = '/home/DEPLOYER/APPNAME/current/log/resque-scheduler-worker.log' # Change | |
| # restart if memory gets too high | |
| w.transition(:up, :restart) do |on| | |
| on.condition(:memory_usage) do |c| | |
| c.above = 100.megabytes | |
| c.times = 2 | |
| end | |
| end | |
| # determine the state on startup | |
| w.transition(:init, { true => :up, false => :start }) do |on| | |
| on.condition(:process_running) do |c| | |
| c.running = true | |
| end | |
| end | |
| # determine when process has finished starting | |
| w.transition([:start, :restart], :up) do |on| | |
| on.condition(:process_running) do |c| | |
| c.running = true | |
| c.interval = 5.seconds | |
| end | |
| # failsafe | |
| on.condition(:tries) do |c| | |
| c.times = 5 | |
| c.transition = :start | |
| c.interval = 5.seconds | |
| end | |
| end | |
| # start if process is not running | |
| w.transition(:up, :start) do |on| | |
| on.condition(:process_running) do |c| | |
| c.running = false | |
| end | |
| end | |
| end | |
| # vim: set filetype=ruby: |
| # In unicorn.conf | |
| # -*- coding: utf-8 -*- | |
| listen "/tmp/APPNAME-unicorn.sock" # Change! | |
| worker_processes 3 | |
| pid "tmp/pids/unicorn.pid" | |
| stderr_path "log/unicorn.stderr.log" | |
| stdout_path "log/unicorn.stdout.log" | |
| preload_app true | |
| before_fork do |server, worker| | |
| defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! | |
| old_pid = "#{server.config[:pid]}.oldbin" | |
| if File.exists?(old_pid) && server.pid != old_pid | |
| begin | |
| Process.kill("WINCH", File.read(old_pid).to_i) | |
| Thread.new { | |
| sleep 30 | |
| Process.kill("KILL", File.read(old_pid).to_i) | |
| } | |
| rescue Errno::ENOENT, Errno::ESRCH | |
| # someone else did our job for us | |
| end | |
| end | |
| end | |
| after_fork do |server, worker| | |
| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection | |
| end | |
| # vim:set ft=ruby: |