【　Ruby on Rails 6.0　】 AWS + Nginx + Unicornでデプロイ⑦

# 始めに
前回の内容でNginxというWebサーバーを導入しRailsアプリを本番環境で起動出来ました。
しかし、現状だと開発環境で変更したものを本番環境に反映させるのに工数が多く不便です。
そこで、`Capistrano`という自動デプロイツールを導入しコマンドひとつでデプロイ作業を完了できるように設定していきます。

# 目次

|目次|内容|
|:--:|:--:|
|セクション1|[EC2インスタンス作成](https://qiita.com/anago1030/items/854252bc9b728fe90beb)|
|セクション2|[Linuxサーバー構築](https://qiita.com/anago1030/items/07f7026c0f4c42a63440)|
|セクション3|[データベース設定](https://qiita.com/anago1030/items/79eebdc8474255b962b4)|
|セクション4|[EC2上でGemをインストールし環境変数を設定](https://qiita.com/anago1030/items/0a9a8937421f64f46a44)|
|セクション5|[Railsアプリを起動](https://qiita.com/anago1030/items/36d0da7e25c57d0e5780)|
|セクション6|[Nginxの導入](https://qiita.com/anago1030/items/c4c80a46a75ff306db8d)|
|セクション7|**自動デプロイ**(今回の内容)|
|セクション8|[独自ドメイン取得](https://qiita.com/anago1030/items/5e487ec48fd7c0be86bc)|

## Capistranoの導入
必要なGemをインストールし、Capistranoを動かすために必要な設定ファイルを生成します。

```php:Gemfile（ローカル）
group :development, :test do
  gem 'capistrano'
  gem 'capistrano-rbenv'
  gem 'capistrano-bundler'
  gem 'capistrano-rails'
  gem 'capistrano3-unicorn'
end
```

```php:ターミナル（ローカル）
$ bundle install

# gemを読み込めたら、下記のコマンドを打ちます。
$ bundle exec cap install
```
するとデプロイについての設定を書くファイルが自動で生成されます。

### Capfileを編集
Capfileは、capistrano全体の設定ファイルです。

```php:Capifile
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 }
```

### デプロイについての設定ファイルを編集
`cap installコマンド`を打つと、config/deploy配下にproduction.rbとstaging.rbの2 種類のファイルが生成されます。

production.rbですが２つファイルがあります
❌　config/environment/production.rb
⭕️　config/deploy/production.rb

今回作業はするのはconfig/deploy/production.rbです。

### production.rbを下記のように編集

```php:config/deploy/production.rb
# 最下部に追記
server 'XX.XXX.XX.XXX(Elastic IP)', user: 'ec2-user', roles: %w{app db web}
```

### deploy.rbを編集

```php:config/deploy.rb
# 全て削除して以下を追記
# config valid only for current version of Capistrano
# capistranoのバージョンを記載。固定のバージョンを利用し続け、バージョン変更によるトラブルを防止する
lock '○.○○.○(Capistranoのバージョン)'

# Capistranoのログの表示に利用する
set :application, '○○○(自身のアプリケーション名)'
set :deploy_to, '/var/www/○○○(アプリ名)'

# どのリポジトリからアプリを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のバージョン)' #カリキュラム通りに進めた場合、2.5.1か2.3.1です

# どの公開鍵を利用してデプロイするか
set :ssh_options, auth_methods: ['publickey'],
                  keys: ['~/.ssh/○○○○○.pem（ローカル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
```
以下の5点は書き換えが必須です。

1. 3行目のはご自身のバージョンを記述しましょう。
2. 6行目の<自身のアプリケーション名>はご自身のものを記述しましょう。
3. 9行目の/<レポジトリ名>も同様に、ご自身のもの記述してください。
4. 15行目の<このアプリで使用しているrubyのバージョン>はご自身のものを確認して
記述してください。
5. 19行目の<ローカルPCのEC2インスタンスのSSH鍵(pem)へのパス>も同様に、ご自
身のもの記述してください。

#### Capistranoのバージョン確認
capistranoのバージョンは、gemfile.lockに記載されています。
`capistrano(3.11.0)`ように記載されています。

#### rubyのバージョンの確認
ローカルのターミナルで以下のように確認します。

```php:ターミナル
$ ruby -v

# 実行結果
ruby2.6.5....
```

### unicorn.rbの記述を編集
capistrano導入後はアプリケーションのディレクトリ構造が変化するので以下のように記述を編集します。

```php: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"
```

### Nginxの設定ファイルの記述を編集
同様に、Nginxの設定ファイルもディレクトリで構造が変化しているので編集します。

```php:ターミナル（EC2）
# SSHログインしてから実行
[ec2-user@ip-172-31-25-189 ~]$ $ sudo vim /etc/nginx/conf.d/rails.conf
```

```php:rails.conf
upstream app_server {
  # sharedの中を参照するよう変更(/shared/tmp/sockets/unicorn.sock;)
  server unix:/var/www/○○○○○（アプリケーション名）/shared/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name XX.XXX.XX（Elastic IP）;

  # currentの中を参照するよう変更(/current/public;)
  root /var/www/○○○○○（アプリケーション名）/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    # currentの中を参照するよう変更(/current/public;)
    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;
}
```
編集し終わったら、`escキー`を押して`:wq`で保存します。
Nginxの設定を変更したら、忘れずに再読込・再起動をします。

```php:ターミナル(EC2)
# nginx起動
[ec2-user@ip-172-31-25-189 ~]$ sudo systemctl reload nginx
[ec2-user@ip-172-31-25-189 ~]$ sudo systemctl restart nginx


# nginxのステータスを確認(active runningであれば成功)
$ sudo systemctl status nginx.service
● nginx.service - The nginx HTTP and reverse proxy server
   Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; vendor preset: disabled)
   Active: active (running) since 水 2021-02-17 11:28:00 UTC; 7h ago
 
 
# エラーが出た場合はnginxのエラーログを確認
[ec2-user@ip-172-31-45-167 アプリ名]$ sudo cat /var/log/nginx/error.log

```

### データベースの起動を確認
データベースが立ち上がっていないとデプロイが失敗するので起動します。

```php:ターミナル（EC2）
[ec2-user@ip-172-31-25-189 ~]$ sudo systemctl restart mariadb

# ステータスを確認（active runningなら成功）
[ec2-user@ip-172-31-25-189 ~]$ sudo systemctl status mariadb
```

### unicornのプロセスをkill
自動デプロイを実行する前にunicornのコマンドをkillします。

```php:ターミナル（EC2）
# プロセスを確認
[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

# 一番上のunicorn_rails masterをkillしたいので、下記を実施
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill 17877
```

### ローカルでの修正を全てmasterにpush
ローカルでのコードの変更が、全てmasterにpushされていることを確認しましょう。

## 自動デプロイ実行
これで、ローカルのターミナルからコマンド一発でデプロイできるようになりました。

```php:ターミナル（ローカル）
# アプリケーションのディレクトリで実行する
$ bundle exec cap production deploy
```
エラーがなく完了したらデプロイ完了です！
![スクリーンショット 2021-02-27 7.41.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/772095/3032902c-ddf5-2990-ac33-70f22138ef3f.png)

ブラウザからElastic IPでアクセスすると、アプリケーションにアクセスできます！
確認してみましょう。

### もし途中でエラーが出たら

* **EC2のターミナルで`less log/unicorn.stderr.log`コマンドでエラーログを確認**
* **ローカルでの編集のpushやpullを忘れていないか確認**
* **mariaDBやNginxを再起動してみる**
* **EC2インスタンスを再起動してみる**

# 終わりに
ここまででRailsアプリを本番環境にデプロイする工程が終了しました！
ただ、IPアドレスだと覚えにくいので次回で独自ドメインを取得方法をまとめたいと思います。
お疲れさまでした。。。

次回
[独自ドメイン取得](https://qiita.com/anago1030/items/5e487ec48fd7c0be86bc)