Railsのステージング環境を構築②(Capistranoによるデプロイ)
ここが山場になります。私はここでかなりどん詰まりしました笑
◯Amazon EC2
◯Cent OS 6.2
◯Ruby 1.9.2
◯Rails 3.2.1
◯rvm 1.14.2
◯unicorn 4.3.1
◯Capistrano 2.12.0
◯nginx 1.2.1
◯mysql 5.5.25
unicornほかのインストール(Gemfileに記述)
gem 'unicorn' gem 'capistrano' gem 'capistrano-ext' #=>capistranoを複数環境で状況に分けて使う(https://github.com/jamis/capistrano-ext) gem 'capistrano-unicorn' #=> capistranoからunicornの再起動を行う(https://github.com/sosedoff/capistrano-unicorn) gem 'rvm-capistrano' #=>rvmとcapistranoを併用する際のライブラリ(https://github.com/wayneeseguin/rvm-capistrano) bundle install unicorn -v #=>unicorn v4.3.1 capify . #=> Capfileが作成される
unicornの設定ファイル(config/unicorn/staging.rb)
app_path = '/var/www/プロジェクト名/current' #Capistranoを使う場合、基本的にアプリケーションのパスを設定するときは #最新のリリースへのシンボリックリンクであるcurrentを使う worker_processes 2 working_directory app_path preload_app true timeout 180 stderr_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) stdout_path File.expand_path('log/unicorn.log', ENV['RAILS_ROOT']) pid "#{app_path}/tmp/pids/unicorn.pid" #unicornを立ち上げた時にpidをどのファイルに記録するか。 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("QUIT", File.read(old_pid).to_i) rescue Errno::ENOENT, Errno::ESRCH end end end after_fork do |server, worker| defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection end
説明。
上から数行は単純な設定で、stderr_path,stdout_pathというのはこれも字のごとく標準エラー出力と標準出力をlogに書き出す、
logファイルの指定です。
pidというのはプロセスid。これをファイルで管理するんですが、unicornをstopさせるとき、このプロセスidを見てkillします。もしunicornをストップさせるところで
詰まるようだったら、このpid設定が間違っていることが多いです。
capistrano-extを使用すると、capistranoに引数として環境を渡すことができます。
例) cap staging deploy:update
unicornの場合、通常設定ファイルは
config/unicorn.rb
の位置に置きますが、これだとすべての環境で共通設定になってしまうので、
config/unicorn/環境名.rb
のファイルを作成してやります。共通部分についてはconfig/unicorn.rbに書いてもおkです。
capistranoの設定ファイル(config/deploy.rb)
require 'capistrano/ext/multistage' #=>capistrano-extを使用する際に必要 set :rvm_ruby_string, '1.9.2-p290' require "rvm/capistrano" set :application, "アプリケーション名" set :rvm_type, :system set :rvm_ruby, '1.9.2-p290' set :rvm_gem_home, '/usr/local/rvm/gems/ruby-1.9.2-p290' set :rvm_ruby_path, "/usr/local/rvm/rubies/ruby-1.9.2-p290/bin/ruby" set :repository, "git@github.com:hoge/hoge.git" set :user,'admin' set :password, 'パスワード' set :scm_username, "githubのアカウントID(privateリポジトリの場合のみ)" set :scm_password, "githubのアカウントパスワード(privateリポジトリの場合のみ)" set :sudo_password, 'パスワード' set :deploy_to, '/var/www/アプリケーション名' set :scm, :git set :deploy_via, :checkout default_run_options[:pty] = true #sorry, you must have a tty to run sudoと言われた時の対策 ssh_options[:keys] = %w(~/.ssh/秘密鍵.pem) task :show_uname do run "uname -a" end #webサーバ,dbサーバ等の情報はすべて環境ごとのファイルに書く require 'capistrano-unicorn' #=>capistrano-unicornを使用する際に必要
capistranoの設定ファイル環境ごと(config/deploy/staging.rb)
set :deploy_env, 'staging' set :unicorn_env, 'staging' set :rails_env, 'staging' # Rails上の環境名 set :app_env, 'staging' set :deploy_to, '/var/www/アプリ名' # デプロイ先の絶対パス [:web, :app].each do |type| role type, '54.248.×××.×××' end role :db, '54.248.×××.×××', :primary => true # rake:db:migrateを実行するサーバー task :db_create do run "cd /var/www/アプリ名/current rake db:create RAILS_ENV=staging" end
database.ymlにstagingを追加(config/database.yml)
staging: adapter: mysql2 encoding: utf8 host: 127.0.0.1 username: admin password: パスワード database: アプリ名_staging pool: 5 timeout: 5000 socket: /var/lib/mysql/mysql.sock
もちろんこのファイルは各々の環境に合わせて書いてください。
Capfileに変更加える
#先頭に次の行を加える require 'bundler/capistrano'
これはcapistranoからbundle installするため必要
nginxの設定(/etc/nginx/nginx.conf)
user admin; worker_processes 2; events { worker_connections 1024; } http { upstream backend { server 127.0.0.1:8080; #APサーバのポート番号を指定 } server { listen 80; server_name hogehoge; #待ち受けるドメインを指定 root /var/www/アプリ名/current/public; #=>capistranoを使う場合はcurrentをつけること。間違いやすい include /etc/nginx/mime.types; default_type application/octet-stream; access_log /var/log/access.log; error_log /var/log/error.log; proxy_connect_timeout 60; proxy_read_timeout 60; proxy_send_timeout 60; location ~* ^/assets { expires max; proxy_path http://backend; } location / { if (-f $request_filename){ break; } 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://backend; } location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ { expires 1y; } } }
あとはローカルの端末から
cap staging deploy:setup cap staging deploy:cold
2行目うまくいかなかったら
cap staging db_create
cap staging bundle:install
cap staging db:migrate
cap staging db:seed
cap staging deploy:update
cap staging deploy:restart
など、コマンドを分けてみてどの挙動でおかしくなっているかチェックしてください。
(このへんは私も試行錯誤しながらやったので、手順的に記憶していないが抜けているところがあるかもしれません)
もう少し理解しながら確実にやりたい方は前回の記事からnginxをインストールして、まずunicorn、nginxでrailsアプリが動くところまでを目指すとよいでしょう。(production環境でもいいので)
実際、productionとstagingを分けているのは単純にそうしないとstaging環境でproductionのDBを読みに行ってしまうためで、例えばstagingのサーバのconfig/database.ymlをgitの対象外にしてしまって
productionの部分を書き換えるといった手もありそうですが、その他にもcapistrano側から対象のサーバを分けたりすることを考えてstagingを作成しました。
Rails.envとかでstagingは返ってくるんですが、rails console -e staging などはできないっぽい。
ただ、rake db:migrate RAILS_ENV=stagingは可能。どういうことだろう?