capistranoとは？からインストール、自動デプロイまで(rails)【AWSを無料で独学勉強】

# 自動でデプロイさせて負担を軽減する
デプロイの作業は非常に手間です。
いちいちその作業をすれば、随分な時間が取られてしまいます。
煩わしいので、自動化させましょう

## これまでのデプロイまでの流れを振り返る
ここまでデプロイするための作業をしましたが、簡単に流れを振り返りましょう
1. git push
2. git pull
3. SSH接続
4. アセットコンパイル
5. Unicorn再起動

この一連の流れをすれば、デプロイが完了されます。
なお、この一連の流れをまだしたことがない、自信がないという人は
詳しく解説している下記の記事を閲覧してください。

EC2インスタンスを立ち上げるまでの記事はシリーズ化しているので、こちらをどうぞ
[独学ではじめてAWSのEC2にデプロイする方法①~⑩（インスタンスの作成）](https://qiita.com/nousi/items/f0ab345402362e43db80)


# capistranoとは
この一連のデプロイ作業を自動化させる、様々のツールの一つにcapistranoがあります。
capistranoを利用することでサーバーにログインしなくても""　コマンド一つで　””デプロイできちゃうのですから、非常に楽です。

一度Capistranoにデプロイが成功すれば、簡略してエラーなしにデプロイができます。

## Capistranoの導入

### Gemのインストール

ローカルのwebappにCapistranoのgemを追加しましょう

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

続いて、インストールします

```
$ bundle install
```

gemがインストールできたところで、Capistranoの下記のコマンドを実施

```
$ bundle exec cap install
```

するとファイルが作成されます。

```
railsルート
├─  Capfile
├─  config
│ ├─  deploy
│ │ ├─production.rb
│ │ └─staging.rb
│ └─deploy.rb
└─  lib
    └─capistrano
        └─tasks
```

これらのファイル説明は作業しながら学びましょう

### Capfileを編集
一度ファイルの中身を全部消して、下記のように編集しましょう

```ruby:Capfile
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 }
```

### production.rbを編集
production.rbですが２つファイルがあります

❌　config/environment/production.rb
⭕️　config/deploy/production.rb

今回作業はするのはconfig/deploy/production.rbです
実際に開くと下記の画面が出ます。
![スクリーンショット 2020-01-19 23.44.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455403/fc1e3273-f889-43bd-c57f-7a5e6038a455.png)

このファイルを下記を追記しましょう！（元が全部コメントアウトなので、どこでも可能）

```ruby:config/deploy/production.rb
server '18.○○○.○○.○○○(Elastic IP)', user: 'ec2-user', roles: %w{app db web}
```

### deploy.rbを編集
config/deploy.rbを開くと下記の画面が出ます
![スクリーンショット 2020-01-19 23.54.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455403/6ad0b334-def9-828f-d160-d967e7f0314d.png)


deploy.rbの記述をすべて削除
![スクリーンショット 2020-01-19 23.55.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455403/0a64a19e-f701-9e92-53c5-5ed227574a97.png)

下記を追加します

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

# Capistranoのログの表示に利用する
set :application, '○○○(自身のアプリケーション名)'
set :deploy_to, '/var/○○○（アプリを入れているディレクトリ)/○○○(アプリ名)'

# どのリポジトリからアプリを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

```



貼り付けたテンプレートの一部を修正しましょう


```ruby:config/deploy.rb
lock '<Capistranoのバージョン>'
```

Capistranoのバージョンを確認するために、Gemfile.lockを開きましょう

```ruby:Gemfile.lock
    capistrano (3.11.1)
      airbrussh (>= 1.0.0)
      i18n
      rake (>= 10.0.0)
      sshkit (>= 1.9.0)
```
これでCapistranoのバージョンが(3.11.1)とわかりました。
ではdeploy.rbを修正しましょう


```ruby:config/deploy.rb
lock '3.11.1'
```

rubyのバージョン確認

```
set :rbenv_ruby, '○.○.○(rubyのバージョン)'
```
ターミナルで下記を実行しましょう

```
$ ruby -v

＞　ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin18]
```

○○○のところは、アプリ名などを入れる必要があるので、穴埋めしてください

```ruby:deproy.rb
set :application, '○○○(自身のアプリケーション名)'
set :repo_url,  'git@github.com:○○○(Githubのユーザー名)/○○○（レポジトリ名.git'
keys: ['~/.ssh/○○○○○.pem（ローカルPCのEC2インスタンスのSSH鍵(pem)へのパス　例：~/.ssh/key_pem.pem））'] 
```

### unicorn.rbを編集

```ruby: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"
```
上記のunicorn.rbの記述を下記に変更

```ruby:unicorn.rb
# ../が一つ増えている
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の設定ファイルを編集

```:ターミナル（EC2)
ec2-user@ip-17-242-2-2 アプリ名$ sudo vim /etc/nginx/conf.d/rails.conf
```


そして、capistranoに合わせた参照先に変更します。（詳細はコメントアウトで解説しています。）

```ruby:rails.conf
upstream app_server {
  # sharedの中を参照するよう変更(/shared/tmp/sockets/unicorn.sock;)
  server unix:/var/○○○（アプリをまとめているディレクトリ）/○○○○○（アプリケーション名）/shared/tmp/sockets/unicorn.sock;
}

server {
  listen 80;
  server_name 18.○○○.○○（Elastic IP）;

  # currentの中を参照するよう変更(/current/public;)
  root /var/○○○(アプリをまとめているディレクトリ）/○○○○○（アプリケーション名）/current/public;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
    # currentの中を参照するよう変更(/current/public;)
    root   /var/○○○/○○○○○○（アプリケーション名）/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;
}
```
### Nginxの設定を変更したら、忘れずに再読込・再起動

```ターミナル（EC2)
[ec2-user@ip-172-31-25-189 ~]$ sudo service nginx reload
[ec2-user@ip-172-31-25-189 ~]$ sudo service nginx restart
```

### MySQLの起動を確認

```:ターミナル（EC2)
[ec2-user@ip-172-31-25-189 ~]$ sudo service mysqld restart
```

### unicornのプロセスをkillしよう

```:ターミナル(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してください

## 自動デプロイの実施

```
# アプリケーションのディレクトリで実行する
$ bundle exec cap production deploy
```
すると下記ん画像のように、徐々に処理が進み出す。
[![Image from Gyazo](https://i.gyazo.com/8f382ec3efb5dbdd6256579774283328.png)](https://gyazo.com/8f382ec3efb5dbdd6256579774283328)

## エラーが発生する場合


#### ディレクトリ `/var/www' を作成できません: 許可がありません
[![Image from Gyazo](https://i.gyazo.com/f7642507c5e1ffe6c8bc8133fdc66d9e.png)](https://gyazo.com/f7642507c5e1ffe6c8bc8133fdc66d9e)



```
mkdir stdout: Nothing written
mkdir stderr: mkdir: ディレクトリ `/var/www' を作成できません: 許可がありません
mkdir: ディレクトリ `/var/www' を作成できません: 許可がありません
```

ヒヤリング：手動デプロイはできていたか？
・YES：Capistranoの設定の問題（ここまで進めている以上、できているはず）
・NO：もう一度手動デプロイを確認する必要があるかもしれません。

設定の見直し

```
rails.confとdeploy.rbのパスの確認をしてください。

var/www/アプリ名で設定しているか？
・ディレクトリはwwwの場合、入力間違いがないか？？？
・ディレクトリは"wwwでない"場合、capistranoのデフォルト設定を変更する必要がある。
```

##### EC2でのアプリの保存場所が『　var/www/アプリ名　』でない場合、、
[参考]（https://capistranorb.com/documentation/getting-started/configuration/)

deplory.rbに下記を追加してください。

```ruby:deploy.rb

set :deploy_to, '/var/○○○/アプリ名'
```
capistranoのデフォルト設定では、/var/www/アプリ名が設定されているため、これを変更する必要がある。
そのオプション設定がset :deploy_to, '/var/○○○/アプリ名'である。


#### Master.keyがないエラー（　Missing encryption key to decrypt file with. Ask your team for your master key and write it to　）
このエラーが表示されたということは、『  本番環境にあるmaster.keyをうまく読み込めていない  』ことを意味します。

```
rake stdout: Nothing written
rake stderr: Missing encryption key to decrypt file with. Ask your team for your master key and write it to /var/○○○（アプリを格納しているディレクトリ名）/○○○（アプリ名）/releases/20200121124714/config/master.key or put it in the ENV['RAILS_MASTER_KEY'].
```

なので現状として可能性は二つです。

- master.keyを作成していない。
- master.keyを作成する場所が間違っている。

ここまで作業を進めている人は,master.keyを作成しているはずです。
＞つまり、master.keyの作成場所をまちがている可能性が高いです。

```
# 誤解が生まれやすいmaster.keyの作成場所

✖︎ アプリ名＞config＞master.key
○ アプリ名＞shared＞config＞master.key

```
おそらく、上記のようにmaster.keyの作成場所に誤りがある可能性が高いです。
ですから、

```:ターミナル（EC2）
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ cd shared 
[ec2-user@ip-172-31-23-189 shared ]$ cd config
[ec2-user@ip-172-31-23-189 config ]$ ls
＞ここでmaster.keyがない場合、 master.keyを作成してください。
```
master.keyを作成する場合、、、

```:ターミナル（ローカル）
アプリ名 $ vi config/master.key
＞master.keyを中身がわかります。
＞間違っても編集しないようにしましょう
```
ローカル環境のmaster.keyをコピーしたら、EC2にmaster.keyを作成しましょう

```:ターミナル（EC2）
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ cd shared/config
[ec2-user@ip-172-31-23-189 config ]$ vi master.key
＞編集画面が出るので
＞ローカルのmaster.keyをコピペします。
＞:wpで保存しましょう
```

master.keyを読み込ませるために、deploy.rbに
下記を追加してください

```ruby:deploy.rb
set :linked_files, fetch(:linked_files, []).push("config/master.key")
```

再度自動デプロイしましょう

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

今度はうまくいくはずです。

# 最後に

未経験からエンジニアになるための最強ノウハウを共有しています。
これで知り合い全員エンジニアになったので、未経験からエンジニアになりたい方は
参考にしてみてください
https://note.com/gyu_outputs/n/nfd80b9dab981


[参考：Rails5.2から追加された credentials.yml.enc のキホン](https://qiita.com/NaokiIshimura/items/2a179f2ab910992c4d39)