AWS Capistranoで自動デプロイ

まず普通にローカルでインストールして設定してく

Gemfile

group :development, :test do
  gem 'capistrano'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano3-unicorn'
end

 

一回bundle install

次に bundle exec cap install

色々ファイルができるので説明してく

 

1アプリケーション直下にあるCapfile

Capistranoの機能を提供するコードはいくつかのライブラリ(Gem)に分かれています。そのため、Capistranoを動かすにはいくつかのライブラリを読み込む必要があります。Capfileは、Capistrano関連のライブラリのうちどれを読み込むかを指定できます。

require "capistrano/setup"
require "capistrano/deploy"
require 'capistrano/rbenv'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'

Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }

require により引数としておかれた文字列が指すディレクトリが読み込まれ、その中にデプロイに際して必要な動作が一通り記述されています。

 

2  config/deploy/以下のproduction.rbとstaging.rb

どっちもデプロイする環境別の設定を記述するファイル

今回は本番環境だけ、つまりproduction.rbだけ弄る

config/deploy/production.rb

 

server '<用意した自分のElastic IP>', user: 'ec2-user', roles: %w{app db web}

 

サーバホスト名、AWSサーバーへのログインユーザー名、サーバーロール、SSHの設定、その他のサーバーに基づく任意の設定を記述していくらしい。

 

 

3.config/以下のdeploy.rb

こっちはproduction,stagingどちらの環境にも当てはまる設定を記述する

アプリケーション名、gitのレポジトリ 、利用するSCM、タスク、それぞれのタスクで実行するコマンドなんかを設定する。

 

 とりあえずこの通りしとこうか

t# config valid only for current version of Capistrano
# capistranoのバージョンを記載。固定のバージョンを利用し続け、バージョン変更によるトラブルを防止する
lock '<自分のアプリのCapistranoのバージョン>'

# Capistranoのログの表示に利用する
set :application, '<自身のアプリケーション名>'

# どのリポジトリからアプリをpullするかを指定する
set :repo_url,  'git@github.com:<Githubのユーザー名>/<レポジトリ名>.git'

# バージョンが変わっても共通で参照するディレクトリを指定
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system', 'public/uploads')

set :rbenv_type, :user
set :rbenv_ruby, '<自分のアプリのrubyのバージョン>' 

# どの公開鍵を利用してデプロイするか
set :ssh_options, auth_methods: ['publickey'],
                  keys: ['<ローカルPCのEC2インスタンスSSH鍵(pem)へのパス(例:~/.ssh/key_pem.pem)>'] 

# プロセス番号を記載したファイルの場所
set :unicorn_pid, -> { "#{shared_path}/tmp/pids/unicorn.pid" }

# Unicornの設定ファイルの場所
set :unicorn_config_path, -> { "#{current_path}/config/unicorn.rb" }
set :keep_releases, 5

# デプロイ処理が終わった後、Unicornを再起動するための記述
after 'deploy:publishing', 'deploy:restart'
namespace :deploy do
  task :restart do
    invoke 'unicorn:restart'
  end
end 

 

補足

set:名前, 値;でDSLみたいに定義してる。fetch名前で値が取り出せる。

desc 'hoge'とかtask: hoge do みたいなのはrequireしたものに加えてcap deploy時に実行されるタスクを追加してる感じ

 

 

自動デプロイ後のアプリのディレクトリ構成。(本番環境の方)

アプリケーション直下に三つディレクトリ増えているので把握しとく

1releasesディレクト

デプロイされたアプリを指定した回数分だけ保存しとくとこ。今回は5回分保存してる(set:keep_releasesのとこ)。ここに前のバージョンが入ってるから一つ前に戻す、みたいなことができる。

2currentディレクト

releasesの中で一番新しい物がコピーされて入ってる。要は現在のデプロイの内容だと思っていい。

3 sharedディレクト

バージョンが変わっても共通で参照されるディレクトリが入ってる。

log,public,tmp,vendorディレクトリとかが入ってる

 

 Capistranoに合わせてunicorn.rbを修正

 capistranoでのデプロイ後は、アプリケーションディレクトリ直下にあるcurrentディクトりが動くことにあるので、実際に動くディレクトリを意味するworking_directoryの部分を修正する。またログやpidの指定をshared以下にするなどの修正をする。

具体的には

もともとのconfig/unicorn.rb

 

app_path = File.expand_path('../../', __FILE__)

worker_processes 1

working_directory app_path
pid "#{app_path}/tmp/pids/unicorn.pid"
listen "#{app_path}/tmp/sockets/unicorn.sock"
stderr_path "#{app_path}/log/unicorn.stderr.log"
stdout_path "#{app_path}/log/unicorn.stdout.log"

を以下のように変更

# ../が一つ増えている
app_path = File.expand_path('../../../', __FILE__)

worker_processes 1
# currentを指定
working_directory "#{app_path}/current"

# それぞれ、sharedの中を参照するよう変更
listen "#{app_path}/shared/tmp/sockets/unicorn.sock"
pid "#{app_path}/shared/tmp/pids/unicorn.pid"
stderr_path "#{app_path}/shared/log/unicorn.stderr.log"
stdout_path "#{app_path}/shared/log/unicorn.stdout.log"

 

そもそもapp_path = File.expand_path('../../../', __FILE__)って何やねん

https://qiita.com/msy-naka/items/43c70e470a63f82b53a7

https://maeharin.hatenablog.com/entry/20130104/p1 

このあたりの記事に参考にして、多分

app_pathがちゃんと(多分)EC2インスタンのトップからのパス返すように../で上の階層に戻ってる感じなんだけど、動くのがcurrentの予定だから一個深くなったので、動く予定のファイルからちゃんと一番上(/var/www/アプリ/current)まで戻った上で__FILE__でファイル名までのパスを返すようにしてるって感じだと思う。この感じだと__FILE__って絶対パス返すもんなのかと思ったけど、必ずしも絶対パスとは限らんらしい。とりあえずこのくらいの理解でいいか。

 

 

Nginxの方もCapistranoに合わせて修正する

こちらも今までvar/www/以下のアプリと連携していたものを、

var/www/アプリ/currentとかshared

と連携するように設定する

webサーバーはEC2のサーバー内にあるのでそちらで

$ sudo vim /etc/nginx/conf.d/rails.conf

開くと現状

rails.conf

upstream app_server {
  server unix:/var/www/<アプリケーション名>/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name <Elastic IPを記入>;

# クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

  root /var/www/<アプリケーション名>/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}

 

こんな感じになってるだろうから、ガッツリ修正して

upstream app_server {
  # sharedの中を参照するよう変更
  server unix:/var/www/<自分のアプリケーション名>/shared/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name <自分のElastic IPを記入>;

# クライアントからアップロードされてくるファイルの容量の上限を2ギガに設定。デフォルトは1メガなので大きめにしておく
  client_max_body_size 2g;

  # currentの中を参照するよう変更
  root /var/www/<自分のアプリケーション名>/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    # currentの中を参照するよう変更
    root   /var/www/<自分のアプリケーション名>/current/public;
  }

  try_files $uri/index.html $uri @unicorn;

  location @unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;
    proxy_pass http://app_server;
  }

  error_page 500 502 503 504 /500.html;
}

こんな感じに 修正

設定したら再起動

ec2-user@ip-172-31-25-189 ~]$ sudo service nginx reload
[ec2-user@ip-172-31-25-189 ~]$ sudo service nginx restart

 

自動デプロイを開始する

MySQLがたちがってないと失敗するので再起動しとく

[ec2-user@ip-172-31-25-189 ~]$ sudo service mysqld restart
Unicornのプロセスをkillしとく
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn
 
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill <確認したunicorn rails masterのPID(上記では17877)>
...

 

ローカルのターミナルい戻り以下のコマンドで自動デプロイを実行する

(もちろんローカルの変更はpushしてある状態で)

 アプリケーションのディレクトリで実行する
$ bundle exec cap production deploy

 

エラーが表示されずに終われば成功。ただし、メモリ不足で落ちることもあるみたいなのでもう一度試す。それでもおかしければ不備がないか確認する。

(デフォでsshのエラー出るから注意↓サーバー起動時にssh鍵の設定がおかしくなるっぽい)

https://qiita.com/aoitrain/items/90036ec9c24f0566711e 

 

最後にブラウザからIPアドレスにアクセスして確認終了

以降はローカルの変更をリモートリポジトリにpushした後に

bundle exec cap production deploy

で反映される

 

 

 

 

追記予定

まだ必要かわからんけどとりあえず

https://qiita.com/tanakayo/items/9d5e091ce5ce52bbdc9a

とか読むことになりそうな気がする