さくらVPS Capistrano編
基本設定、開発環境設定に引き続き、今回はCapistranoを導入して自動デプロイできるように設定。unicorn+nginx周りの設定も変更して快適にデプロイできるようになりました。
リモートリポジトリの作成
リモートサーバーにリポジトリを作成します。
今回は全て同じサーバーでやるので、自分のホームディレクトリ直下に作りました。
$ mkdir -p /home/ntaku/git/sample $ cd ~/git/sample $ git --bare init
後からcapistranoでアプリを配置するためのディレクトリも作成しておきます。
# mkdir /var/www
プロジェクト作成
ここからはローカルで。
新規プロジェクトを作成して、テスト用のコントローラーを追加します。
$ rails new sample -d mysql $ cd sample $ rails g controller top index
先ほど作った空のgitリポジトリを取得して、git関連のファイルを上記の新規プロジェクトに移します。
$ git clone ssh://ntaku@xxx.xxx.xxx.xxx:10022/home/ntaku/git/sample sample_git $ mv sample_git/.git sample $ rm -rf sample_git
Capistrano設定
まずはBundlerを使ってunicornとcapistranoをインストールします。
# /sample/Gemfile
source 'http://rubygems.org' gem 'rails', '3.1.1' gem 'mysql2' group :assets do gem 'sass-rails', '~> 3.1.4' gem 'coffee-rails', '~> 3.1.1' gem 'uglifier', '>= 1.0.3' end gem 'jquery-rails' gem 'unicorn' group :deployment do gem 'capistrano' gem 'capistrano_colors' end
$ bundle install
capifyでcapistranoの設定ファイルを生成します。
$ capify . [add] writing './Capfile' [add] writing './config/deploy.rb' [done] capified!
デプロイスクリプトを修正します。
とりあえずこんな感じで動作しました。
# /sample/config/deploy.rb
# capistranoの出力がカラーになる require 'capistrano_colors' # cap deploy時に自動で bundle install が実行される require "bundler/capistrano" # RVMを利用している場合は必要 $:.unshift(File.expand_path('./lib', ENV['rvm_path'])) require 'rvm/capistrano' set :rvm_ruby_string, '1.9.2' set :rvm_type, :user # リポジトリの設定 set :application, "sample" set :scm, :git set :repository, "ssh://ntaku@xxx.xxx.xxx.xxx:10022/home/ntaku/git/#{application}" set :branch, "master" set :deploy_via, :remote_cache set :deploy_to, "/var/www/#{application}" set :rails_env, "production" # SSHの設定 set :user, "ntaku" ssh_options[:port] = "10022" ssh_options[:forward_agent] = true default_run_options[:pty] = true # role (全部同じIPでOK) role :web, "xxx.xxx.xxx.xxx" role :app, "xxx.xxx.xxx.xxx" role :db, "xxx.xxx.xxx.xxx", :primary => true # precompile load 'deploy/assets' # cap deploy:setup 後、/var/www/sample の権限変更 namespace :setup do task :fix_permissions do sudo "chown -R #{user}.#{user} #{deploy_to}" end end after "deploy:setup", "setup:fix_permissions" # Unicorn用に起動/停止タスクを変更 namespace :deploy do task :start, :roles => :app do run "cd #{current_path}; bundle exec unicorn_rails -c config/unicorn.rb -E #{rails_env} -D" end task :restart, :roles => :app do if File.exist? "/tmp/unicorn_#{application}.pid" run "kill -s USR2 `cat /tmp/unicorn_#{application}.pid`" end end task :stop, :roles => :app do run "kill -s QUIT `cat /tmp/unicorn.pid`" end end
unicornの設定
unicornも設定ファイルがアプリ内にあるので合わせて設定しておきます。
ソケットファイル名、ログの出力場所など。
# /sample/confit/unicorn.rb
application = 'sample' listen "/tmp/unicorn_#{application}.sock" pid "/tmp/unicorn_#{application}.pid" worker_processes 4; timeout 30 preload_app true if ENV['RAILS_ENV'] == 'production' shared_path = "/var/www/#{application}/shared" stderr_path "#{shared_path}/log/unicorn.stderr.log" stdout_path "#{shared_path}/log/unicorn.stdout.log" end before_fork do |server, worker| # マスタープロセスの接続を解除 if defined?(ActiveRecord::Base) ActiveRecord::Base.connection.disconnect! end # 古いマスタープロセスをKILL old_pid = "/tmp/unicorn.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 did our job for us end end end after_fork do |server, worker| # preload_app=trueの場合は必須 if defined?(ActiveRecord::Base) ActiveRecord::Base.establish_connection end end
デプロイ
修正したファイルを全てコミットします。
$ git add . $ git commit -m 'first import' $ git push origin master
セットアップを実行すると、/var/wwwにベースのディレクトリが作成されます。(初回のみでOK)
$ cap deploy:setup ./sample ./sample/shared ./sample/shared/system ./sample/shared/pids ./sample/shared/log ./sample/releases
deployコマンドでファイルを配置します。
ここでbundle install、rake assets:precompile も実行されます。
$ cap deploy
最後にmigrateでDB変更を反映します。この際、DBがないとエラーになるので先に作成しておく必要があります。それでも失敗するという場合はdatabase.ymlを確認。mysql.sock辺りではまりました..
$ cap deploy:migrate
これで準備が整ったのでunicornを起動します。
$ cap deploy:start
設定に問題がなければ複数プロセス起動されているはずです。
[ntaku@xxx www]$ ps -ef | grep unicorn ntaku 5552 1 12 20:13 ? 00:00:05 unicorn_rails master -c config/unicorn.rb -E production -D ntaku 5557 5552 0 20:13 ? 00:00:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D ntaku 5560 5552 0 20:13 ? 00:00:00 unicorn_rails worker[1] -c config/unicorn.rb -E production -D ntaku 5563 5552 0 20:13 ? 00:00:00 unicorn_rails worker[2] -c config/unicorn.rb -E production -D ntaku 5566 5552 0 20:13 ? 00:00:00 unicorn_rails worker[3] -c config/unicorn.rb -E production -D
確認後、一旦止めます。
$ cap deploy:stop
nginxの設定
最後にnginxからunicornのソケットに接続できるように設定します。
参考サイトを見ながら入れたのでまだよく分かっていないパラメタもちらほら。
# /etc/nginx/nginx.conf
user nginx nginx; worker_processes 4; pid /var/run/nginx.pid; events { worker_connections 1024; multi_accept on; } http { sendfile on; tcp_nopush on; tcp_nodelay off; include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; gzip on; gzip_disable "msie6"; gzip_proxied any; gzip_min_length 500; gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; # Virtual Host Configs #include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; }
今回作成したアプリ用の設定ファイルを追加します。
ソケット名をunicornで設定したものと合わせる必要があります。
# /etc/nginx/sites-available/default
upstream unicorn_app { server unix:/tmp/unicorn_sample.sock fail_timeout=0; } server { listen 80; server_name _; root /var/www/sample/current; access_log /var/log/nginx/sample_log; rewrite_log on; location / { # 全リクエストをUNIX socketへ proxy_pass http://unicorn_app; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 10m; client_body_buffer_size 128k; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; } # Rails 3.1's asset pipe_line用に何か必要かもしれないらしい.. location ~ ^/(images|javascripts|stylesheets|system)/ { root /var/www/sample/current/public; expires max; break; } }
nginxを起動します。
# /etc/init.d/nginx start
最終確認
もう一度 cap deploy:start して、ブラウザからアクセスするとつながります。
http://xxx.xxx.xxx.xxx/top/index