CapistranoでBitBucketのプライベートリポジトリ上のRailsアプリをデプロイする on CentOS7

これまでに、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コマンドで一発デプロイ出来るので楽です。

参考