これまでに、MacOSXでの開発環境の構築と、さくらのVPSを使った公開サーバーの構築をしてきたので、今回はやっと開発環境で作ったRailsアプリを公開サーバーにデプロイしてみます。
デプロイはCapistranoというツールがメジャーな感じなのでそれを使います。HTMLとかPHPはサーバーにアップしたらそれだけで見れるのですが、Ruby on Railsは公開サーバー上で色々とコマンドはしらせたり設定したりと、色々しないと動かないようで、それらを自動でやってくれるツールのようです。以下のサイトがよくまとまってます。
ここでは、直接開発環境からアップするのではなく、一度Bitbucketのプライベートリポジトリを経由して公開サーバーにアップすることにします。
例として前回までに作ったプロジェクトHelloRailsを使います。
ちなみに、さくらのVPSでのサーバーの構築については以下。
目次
Capistranoをインストール
Gemfileに以下を記載します。
group :development do
gem 'capistrano'
gem 'capistrano-rbenv' #デプロイ先のrbenv環境をベースとするため
gem 'capistrano-bundler' #デプロイ先でbundle installを実施するため
gem 'capistrano-rails' #アセットパイプラインのプリコンパイル用
gem 'capistrano3-unicorn' # unicornのコントロール
gem 'capistrano-maintenance' # メンテナス画面の表示
end
$ bundle install
$ bundle exec cap install
Capifileを編集
Capfileが出来ているので、以下のように編集。というか、コメントアウト(#)を外します。unicornは追記します。
require 'capistrano/setup'
require 'capistrano/deploy'
require "capistrano/scm/git"
install_plugin Capistrano::SCM::Git
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/migrations'
require "capistrano3/unicorn"
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
deploy.rbを編集
config/deploy.rbを以下のように編集します。
lock "~> 3.10.2"
set :application, "HelloRails"
set :repo_url, "git@bitbucket.org:kysusfour/HelloRails.git" # Bitbucket
set :deploy_to, "/usr/share/nginx/HelloRails"
set :rbenv_path, '/usr/local/src/rbenv'
set :rbenv_ruby, '2.4.3' #サーバで利用するrubyのバージョンを指定
set :default_env, {
rbenv_root: "#{fetch(:rbenv_path)}",
path: "#{fetch(:rbenv_path)}/shims:#{fetch(:rbenv_path)}/bin:$PATH"}
set :bundle_without, [:development] #Gemfile内のdevelopmentグループ以外を対象にする
# capistrano3-unicornの設定
set :unicorn_pid, "/usr/share/nginx/HelloRails/shared/tmp/unicorn.pid"
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
desc 'Restart application'
task :restart do
on roles(:app), in: :sequence, wait: 5 do
invoke 'unicorn:restart'
end
end
end
capistrano3-unicornの設定で、pidの場所をsharedディレクトリにしておかないと、restart時にうまくkill出来ないらしいので、未確認ですがsharedディレクトリに設定しています。上記のようにshared/tmpを設定する場合、tmpディレクトリは自分で作らないといけません。
production.rbを編集
config/deploy/production.rbを編集します。
role :app, %w{ky@susfour.net} # アプリケーションサーバ
role :web, %w{ky@susfour.net} # webサーバ
role :db, %w{ky@susfour.net} # DBサーバ
server "susfour.net",
user: "ky",
roles: %w{web app},
ssh_options: {
user: "ky", # overrides user setting above
keys: %w(/Users/ky/.ssh/id_rsa),
forward_agent: false,
auth_methods: %w(publickey)
}
unicorn/production.rbを編集
capistrano3-unicornのconfigファイルを設定します。デフォルトで、config/unicorn/RAILS_ENV.rbを読み込む様になっていますので、config/unicorn/production.rbを作成します。
# paths
app_path = "/usr/share/nginx/HelloRails"
shared_path = "#{app_path}/shared"
working_directory "#{app_path}/current"
pid "#{shared_path}/tmp/unicorn.pid"
# listen
listen "#{shared_path}/tmp/unicorn.sock"
# logging
stderr_path "log/unicorn.stderr.log"
stdout_path "log/unicorn.stdout.log"
# workers
worker_processes 3
# use correct Gemfile on restarts
before_exec do |server|
ENV['BUNDLE_GEMFILE'] = "#{app_path}/current/Gemfile"
end
# preload
preload_app true
before_fork do |server, worker|
# the following is highly recomended for Rails + "preload_app true"
# as there's no need for the master process to hold a connection
if defined?(ActiveRecord::Base)
ActiveRecord::Base.connection.disconnect!
end
# Before forking, kill the master process that belongs to the .oldbin PID.
# This enables 0 downtime deploys.
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
# someone else did our job for us
end
end
end
after_fork do |server, worker|
if defined?(ActiveRecord::Base)
ActiveRecord::Base.establish_connection
end
end
ここでもpidとsocketのアドレスにsharedディレクトリを設定します。shared/tmpを設定した場合、tmpディレクトリは自分で作っておかないとエラーがー出ます。
Bitbucketにプライベートリポジトリを作ってPushする。
以上で開発環境での設定は終わったので、Bitbucketに上げます。あらかじめ、開発環境と公開サーバーからBitbucketにSSH鍵認証でアクセスできるように公開鍵の登録もしておきます。
.gitignoreの作成
# Ignore bundler config.
/.bundle
# Ignore bundler gems.
vendor/bundle
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*.log
/tmp
# Ignore other unneeded files.
doc/
*.swp
*~
.project
.DS_Store
.idea
.secret
Bitbucketにpush
Bitbucketで予め空のリポジトリを作成しておきます。ここではHelloRailsリポジトリを作成しておきます。リポジトリ作成後、Railsアプリケーションをpushします。
$ git init
$ git add .
$ git commit -m 'initial commit'
$ git remote add origin git@bitbucket.org:kysusfour/HelloRails.git
$ git remote -v
$ git push origin master
Capistranoでデプロイする
すべての準備は整いましたので、capistranoでデプロイします。
$ bundle exec cap production deploy:check --trace
$ bundle exec cap production deploy --trace
エラーが出ずに終われば無事デプロイ出来ています。
最後に公開サーバーでの設定です。
nginx.confの編集
nginx.confと書いておきながら、実際にはconf.d/HelloRails.confを作成します。conf.d/*.confは自動で読み込まれるので。
upstream unicorn {
server unix:/usr/share/nginx/HelloRails/shared/tmp/unicorn.sock;
}
server {
listen 80;
server_name hellorails.susfour.net;
root /usr/share/nginx/HelloRails/current/public;
try_files $uri/index.html $uri @unicorn;
client_max_body_size 100m;
error_page 500 502 503 504 /500.html;
location @unicorn {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-CSRF-Token $http_x_csrf_token;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_pass http://unicorn;
}
}
server unix:には、capistrano3-unicornで設定したsocketと同じパスを設定します。最初POSTが通らなかったのですが、proxy_set_headerに”X-CSRF-Token $http_x_csrf_token”と”X-Forwarded-Proto $scheme”を設定したら無事通りました。
上記作成したらNginxをrestratします。
server_nameは予めドメインを取得してDNSの設定まで終わらせておきます。私はMuuMuuドメインです。年間69円からドメインが取得できてお得。
データベースの作成
あらかじめ公開サーバーに使用するデータベースを作成しておきます。phpMyAdminを使うと簡単に作れます。
秘密トークンを設定
config/secret.ymlに記載されているとおり、production環境では環境変数SECRET_KEY_BASEの値を読み込んで使う事になっています。
$ rails secret
で長いkeyが出力されますので、その値を、
$ export SECRET_KEY_BASE=・・・
で、設定します。私は、/etc/profile.d/にrails.shを作って上記を保存しています。
これで、http://hellorails.susfour.net/にアクセスすれば、開発環境と同じ画面が表示されます。
あー、疲れた。疲れたけど、最初の設定さえ終わればあとはcapコマンドで一発デプロイ出来るので楽です。