Capistranoを噛み砕く

##近況報告
　実はコーヒーマイスターを前職で取得した経緯がありまして，若干のコーヒーの知識があるので，少しひけらかしたいと思います。まず，コーヒーってどんな飲み物のイメージがあります？多分，**苦いイメージ**ですよね。では，現在世界的に高品質なコーヒーはどのように評価されているでしょうか。実は**苦さの評価はありません。酸味の評価が主流です。**

　理由はいたって簡単。**苦味は焙煎によって生まれるものであり，酸味はコーヒー豆がそもそも持っているものだから**です。細かい説明はしませんが，生のコーヒー豆は食べられたものではありません，それを美味しくするために火を入れます。その時に豆の成分が焦げて苦味になります。酸味は熱によって分解されていくので，結果として深煎りのコーヒーは酸味のないものになります。一方，苦味は焙煎度合いや焙煎師の腕，設備により変化します。ということは，豆が本来持っている酸味が評価の基準になるのはまあ納得ですね。

　ただ，この評価はスペシャリティコーヒー（世界のコーヒー生産のうち１０％程度に該当する）の概念が生まれた１０数年前のものであり，以前は苦味，そもそもそんな評価なかったかも。。。今後も同じ評価をしていくとは限りません。やはり常に情報は更新されていきます。だから，常にアンテナを張っていないと時代遅れになっちゃいますね。全てが動いているのに自分が動かなかったら動いている相手から見たら不安定です。だから動くこと，不安定であることこそが安定ってね。

#今回の目標
Capistranoで実施していることの言語化

##大まかな流れ
・Capistranoについて
・Capistrano導入
・各ファイルの設定

##事前準備
デプロイ環境整備
rails5.2以降ならマスターキーを本番環境に環境変数にして入れといてね
ruby 2.5.1

###Capistranoについて
一言で言えば，自動デプロイツールです。

デプロイには
SSH内の情報（アプリケーション）の更新
SSH接続
アセットコンパイル更新
Unicorn再起動
といくつかコードを打ち込んでいく必要があります。ただCapistranoを導入さえできれば，
** bundle exec cap production deploy**
これだけで上の作業が終了します。
~~個人的にはCircleCiを勉強して導入したかったのですが，間に合わずカリキュラムのこちらを~~
###Capistrano導入
railsにおいてCapistranoにはGemが存在します。そこからチョチョイと生成しましょう。

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

```terminal.
$ bundle install
$bundle exec cap install
⇨gemfileにあるものを参照してcap(istrano)の関連ファイルをインストール
```
これで１つのフォルダと２つのファイルが生成されます

◆capfile----capistranoで実行することを決めるファイル
◆deploy-----デプロイする環境ごとに設定されるファイル
　・staging.rb-----ステージング環境（つまり開発環境，テスト環境）に適用される
　・pruduction.rb--本番環境に適用される
◆deploy.rb--デプロイする内容を決めるフォルダ
capfileで実行することをきめて，残りがGithubへの接続に必要なsshキーの指定、デプロイ先のサーバのドメイン、AWSサーバへのログインユーザー名、サーバにログインしてからデプロイのために何をするか、といった設定が入るわけです。

###各ファイルの設定
**capfile**

```capfile.
require "capistrano/setup"　←準備しますー（これ抜けてたら動かない）
require "capistrano/deploy"　←デプロイ実行するねー
require 'capistrano/rbenv'　←rbenvの状態みるね
require 'capistrano/bundler'　←必要なGem確認するね
require 'capistrano/rails/assets'　←アセットファイルをコンパイルするね
require 'capistrano/rails/migrations'　←DB：migrateするね
require 'capistrano3/unicorn'　←unicorn再起動するね
Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r } 
⇨ディレクトリ内の.rakeを昇順で抽出
```
に編集
**pruduction.rb**

```pruduction.rb
 server '12.345.678.90'←用意したElastic I, user: 'ec2-user', roles: %w{app db web} |
```
「どのサーバーつなぐ？」，「ユーザー名は？」「マイグレートするのは（データベース選択）」
staging.rbは今回必要ないので無視

**deploy.rb**

```deploy.rb
# 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: ['****.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　:xx, xx ⇨DSL（Domain-Specific Language）の一種
ある特定の処理における効率をあげるために特化した形の文法を擬似的に用意したプログラムです。
上記のset :名前, 値について、これは言わば変数のようなものです。
例えばset: Name, 'value' と定義した場合、fetch Name とすることで 'Value'が取り出せます。
また、一度setした値はdeploy.rbやproduction.rbなどの全域で取り出すことができます。
また、ファイル内には、desc '◯◯'やtask:XX doといった記述がよく見受けられます。これは、先ほどCapfileでrequireしたものに加えて追加のタスクを記述している形です。ここで記述したものもcap deploy時に実行されることとなります。

Capistranoによる自動デプロイ後のディレクトリ構成について
　一度Capistranoによる自動デプロイを実行すると、本番環境のアプリケーションのディレクトリが変化します。
Capistranoによるアプリのバックアップなど、複数のディレクトリが作成されます。その中でも特に重要なのが、releases、current、sharedディレクトリです。

releasesディレクトリ
　capistranoを通じてデプロイされたアプリは、releasesというフォルダにひとまとめにされます。
ここに過去分のアプリが残っていることにより、デプロイ時に何か問題が発生しても一つ前のバージョンに戻ったりすることができます。
そして、その過去分の保存数を指定しているのがdeploy.rbのset :keep_releasesの記述となります。今回は5つ、過去のバージョンを保存するよう設定しました。

currentディレクトリ
　releasesフォルダの中で一番新しいものが、自動的にcurrentというフォルダ内にコピーされているような状態になります。そのため、このcurrent内に入っているアプリの内容が、現在デプロイされている内容ということになります。
db：seedもここに入れないと反映されない。
sharedディレクトリ
　バージョンが変わっても共通で参照されるディレクトリが格納されるディレクトリです。具体的には、log、public、tmp、vendorディレクトリが格納されます。

```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の設定ファイルも変更が必要です。

これまでは/var/www/以下のアプリケーションに対して連携を設定していたので、/var/www/chat-space以下のcurrent、sharedなどのディレクトリと連携するように設定を変更する必要があります。全て消して編集

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

```vim
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;
}
```

各サーバー再起動
```
$ sudo service nginx reload
$ sudo service nginx restart
$ sudo service mysqld restart
$ ps aux | grep unicorn
$ kill [master number]
```

$ bundle exec cap production deploy