Rails 4.2 + Capistrano3 + Unicorn + Nginx でホットデプロイ環境構築
Capistrano3 + Unicorn + Nginx でのデプロイ環境構築を試してみる。
今回は Ubuntu 12 の環境で行う。
リモートのGITサーバの準備や外部にWEBサーバ等を準備するのが面倒なので、
全てローカルで完結するように試してみる。
準備
# rvm list known Ubuntu 12 のせいで rvm で Ruby 1.9.3 までしかインストールできないので思考錯誤。 rvmsudo(MultiUserモード)を使えるように設定 # sudo usermod -G rvm vagrant # vim ~/.bashrc umask 002 #読み込まれる位置に追加 # export rvmsudo_secure_path=1 rvm のバージョンを上げる # rvmsudo rvm get head # rvmsudo rvm reload # rvm list known # rvmsudo rvm install 2.1.5 エラーが出てしまう。 apt で利用するリポジトリにソースがないっぽ。 下記を見てみる。 # rvm help mount 直接ソースをマウントする。 # rvmsudo https_proxy=${https_proxy} rvm mount -r https://rvm.io/binaries/ubuntu/12.04/x86_64/ruby-2.1.5.tar.bz2 # rvm use ruby-2.1.5
Rails 4.2 をインストール
下記をワークディレクトリとして作業する。
Rails 4.2 をbundle install
する。
# cd /home/vagrant/local_proj # vim Gemfile
source 'https://rubygems.org' gem 'rails', '4.2.1'
# bundle install --path vendor/bundle
これでワークディレクトリ上でbundler
を通して、
Rails4.2を使えるようになった。
Rails のアプリ作成と必要Gemのインストール
テスト用のアプリを作る。
# cd /home/vagrant/local_proj # bundle exec rails new test_app
テスト用アプリに必要GEMをインストール。
# cd test_app # vim Gemfile
下記を最下部に追加。
# gem 'debugger' #ruby 2.1と相性が悪いのでコメントアウト gem 'therubyracer' # rake 実行で ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime.に対応するため gem 'unicorn' gem 'capistrano' gem 'capistrano-rails' gem 'rvm-capistrano' gem 'capistrano-bundler' gem 'capistrano3-unicorn' gem 'rvm1-capistrano3', require: false
# bundle install --path vendor/bundle
rake の実行でエラーが出るので、Ruby2.1.5向けにインストール。
# rvm use 2.1.5 # rvmsudo gem install 'rake'
DB初期化。
# bundle exec rake db:setup # ls db development.sqlite3 seeds.rb test.sqlite3
scaffold で動作確認するためのコントローラー等を用意しておく。
マイグレーションは production 環境以外で実行。
# bundle exec rails g scaffold test_dayo name:string # bundle exec rake db:migrate # RAILS_ENV=test bundle exec rake db:migrate
動作確認する。
ちなみに Rack 1.6以上からは-b 0.0.0.0
でオプション指定しないと、
ホストOSからゲストOSへのアクセスができない。(セキュリティ対策)
詳細は下記で。
» Rails4.2beta1をインストールして最初にはまったこと TECHSCORE BLOG
# bundle exec rails s -b 0.0.0.0 http://192.168.33.11:3000/test_dayos ↑へアクセスできることを確認。
Unicorn の設定
必要最低限の Nginx と連携を取る設定ファイルを準備する。
後々分かったことだが、pid ファイル等を current ディレクトリで管理してしまうと Unicorn のホットデプロイに支障が出るため、
production 環境では shared ディレクトリで pid ファイル等を管理するように切り分けた。
# vim config/unicorn.rb def rails_root File.expand_path('../../', __FILE__) end def rails_env_ ENV['RAILS_ENV'] || "development" end def shared_path "/home/deployer/local_proj/shared" end def path_by_rails_env if rails_env == "production" shared_path else rails_root end end worker_processes 2 working_directory rails_root listen "#{path_by_rails_env}/tmp/#{rails_env}_unicorn.sock" pid "#{path_by_rails_env}/tmp/#{rails_env}_unicorn.pid" stderr_path "#{rails_root}/log/#{rails_env}_unicorn_error.log" stdout_path "#{rails_root}/log/#{rails_env}_unicorn.log" preload_app true
GIT リポジトリをローカルに作成
git のリモートリポジトリをローカルで作成してみる。
# cd /home/vagrant # mkdir local_proj.git # git init --bare
ローカルのリモートリポジトリに push する。
# cd /home/vagrant/local_proj/test_app # git init # git remote add origin /home/vagrant/local_proj.git
.gitignore に下記を追加。
vendor/bundle *.swp
test_app を全部コミット、プッシュする。
# git add . # git commit -m "first commit" # git push origin master
Production 用環境準備
production 用に deployer ユーザを作成、ソースを持ってきて、セットアップする。
起動してアクセスしてみるも、シークレットキーでエラー。
# sudo adduser deployer # sudo usermod -G rvm deployer # su - deployer # cd ~ # git clone /home/vagrant/local_proj.git # cd local_proj # bundle install --path vendor/bundle # RAILS_ENV=production bundle exec rake db:setup # RAILS_ENV=production bundle exec rails s -b 0.0.0.0 http://192.168.33.11:3000/test_dayos へアクセスすると下記エラー ERROR RuntimeError: Missing `secret_token` and `secret_key_base` for 'production' environment, set these values in `config/secrets.yml`
シークレットキーを設定する。
# vim ~/.profile export SECRET_KEY_BASE=aiueo #追加
# source ~/.profile # RAILS_ENV=production bundle exec rails s -b 0.0.0.0 http://192.168.33.11:3000/test_dayos へアクセスできることを確認。 # rm -rf local_proj 一旦、production で動作確認できたので消す、あとで Capistrano からデプロイする。
Nginx のインストールと設定
# sudo aptitude install nginx
Unicorn と development 環境と連携する設定。
# vim /etc/nginx/conf.d/development.conf upstream development_unicorn { server unix:/home/vagrant/local_proj/test_app/tmp/development_unicorn.sock; } server { listen 8080; server_name test_app; root /home/vagrant/local_proj/test_app/public; access_log /var/log/nginx/development_test_app_access.log; error_log /var/log/nginx/development_test_app_error.log; try_files $uri/index.html $uri @unicorn; location @unicorn { 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://development_unicorn; } }
Unicorn と production 環境と連携する設定。
各ディレクトリやファイルの指定は Capistrano でデプロイ実行後のディレクトリ構成を考慮。
# vim /etc/nginx/conf.d/production.conf upstream production_unicorn { server unix:/home/deployer/local_proj/shared/tmp/production_unicorn.sock; } server { listen 80; server_name test_app; root /home/deployer/local_proj/current/public; access_log /var/log/nginx/production_test_app_access.log; error_log /var/log/nginx/production_test_app_error.log; try_files $uri/index.html $uri @unicorn; location @unicorn { 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://production_unicorn; } }
Nginx を起動しておく。
# sudo nginx
vagrant ユーザで development 環境を起動。
# bundle exec unicorn_rails -c config/unicorn.rb -E development http://192.168.33.11:8080/test_dayos へアクセスできることを確認する。
Capistrano の設定
vagrant ユーザ(development 環境)で設定していく。
# cd /home/vagrant/local_proj/test_app # bundle exec cap install STAGES=production
Capfile を編集。
コメントアウトを以下のように外して、require 'rvm1/capistrano3'
とrequire 'capistrano3/unicorn'
を追加。
# vim Capfile ... # require 'capistrano/rvm' # require 'capistrano/rbenv' # require 'capistrano/chruby' require 'rvm1/capistrano3' require 'capistrano/bundler' require 'capistrano/rails/assets' require 'capistrano/rails/migrations' # require 'capistrano/passenger' require 'capistrano3/unicorn' ...
config/deploy.rb を編集する。
下記のように変数をセット。
# vim config/deploy.rb ... set :application, 'test_app' set :repo_url, '/home/vagrant/local_proj.git' set :deploy_to, '/home/deployer/local_proj' # MultiUser の場合 :system, SingleUser の場合 :user set :rvm_type, :system set :rvm1_ruby_version, '2.1.5' # rvm-auto.sh を配置・実行するためのパス、書込権限に注意 set :rvm1_auto_script_path, "/tmp/#{fetch(:application)}" set :default_env, fetch(:default_env).merge!( { # MultiUser モードでインストールした bin/rvm がある場所を指定 "rvm_path" => "/usr/share/ruby-rvm/", http_proxy: "http://example:8080", https_proxy: "http://example:8080" } ) ... after 'deploy:publishing', 'deploy:restart' namespace :deploy do before :starting, 'deploy:mkdir' task :mkdir do on roles(:all) do # pid ファイル等を管理する tmp ディレクトリを作成しておく execute "mkdir -p #{shared_path}/tmp" end end task :restart do # deploy:publishing 処理後に Unicorn の再起動タスクを実行(ホットデプロイ invoke 'unicorn:restart' end ...
本番環境向けの設定。
# vim config/deploy/production.rb server 'localhost', user: 'deployer', roles: %w{web db} role :web, %{deployer@localhost} role :db, %{deployer@localhost} set :unicorn_roles, :web set :unicorn_pid, "#{shared_path}/tmp/production_unicorn.pid" set :unicorn_config_path, "/home/deployer/local_proj/current/config/unicorn.rb" set :default_env, fetch(:default_env).merge!( { secret_key_base: "aiueo", } ) set :unicorn_rack_env, -> { fetch(:rails_env) == "development" ? "development" : "production" } server 'localhost', user: 'deployer', roles: %w{web db}, ssh_options: { user: 'deployer', # overrides user setting above forward_agent: false, auth_methods: %w(password), password: 'deployer' }
Capistrano と Unicorn での設定ファイルを全てコミット、プッシュする。
# git add . # git commit -m "Add unicorn and capistrano setting file." # git push origin master
デプロイしてみる。
# bundle exec cap production deploy # ls /home/deployer/local_proj current/ releases/ repo/ shared/
http://192.168.33.11/test_dayos へアクセスできることを確認。
現状のデプロイだと、sqlite との関係上毎回DBがリセットされるため、 sqlite のファイルを shared 内に入れる。
# vim config/database.yml production: <<: *default database: /home/deployer/local_proj/shared/db/production.sqlite3
デプロイすると、shared 内に sqlite のファイルが作成された。
# git add . # git commit -m 'Modify database.yml' # git push origin master # bundle exec cap production deploy # ls /home/deployer/local_proj/shared/db production.sqlite3
せっかくなのでソースを更新してみる。
# bundle exec rails g migration AddBodyToTestDayo body:text # bundle exec rake db:migrate
コントローラー・モデル・ビューを修正(省略
デプロイしてみる、リロード連打しながらどうなるか。
ホットデプロイ感を味わえるか・・・
チカチカしてうざいけど、ダウンタイムが発生しないでデプロイできることが確認できた。
Unicorn のプロセス管理も capistrano3/unicorn
で簡単にできるようになっているし、
ホットデプロイの環境でサービスを運営してみたいと思った。