EC2のRailsを起動する

##はじめに
「AWSのサーバーを利用する」ための手順を5つに分けて書いています。

記事は以下にまとめておりますのでご確認ください。

①[EC2の初期設定](https://qiita.com/maca12vel/items/902dde37a267ceca1c53)
②[本番環境でデータベースを作成する](https://qiita.com/maca12vel/items/68d6ae3d4308e330847d) 
③[EC2のRailsを起動する](https://qiita.com/maca12vel/items/2a04d39f958b53d687e2) ← イマココ 
④[Webサーバーを設定する](https://qiita.com/maca12vel/items/35f9fb73bb21cb4869fb) 
⑤[デプロイを自動化する](https://qiita.com/maca12vel/items/7b33dd6ea1ad556e3fec)

##EC2上でRailsを起動するための設定
ターミナル（EC2内)で実行
※ 途中で「passphrase」など3段階ほど入力を求められることがあるが、
すべて何も入力せずにEnterキーを押して進む。


```
[ec2-user@ip-***-**-**-*** ~]$ ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ec2-user/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ec2-user/.ssh/id_rsa.
Your public key has been saved in /home/ec2-user/.ssh/id_rsa.pub.
The key fingerprint is:
3a:8c:1d:d1:a9:22:c7:6e:6b:43:22:31:0f:ca:63:fa ec2-user@ip-172-31-23-189
The key's randomart image is:
+--[ RSA 4096]----+
|    +            |
| . . =           |
|  = . o .        |
| * o . o         |
|= *     S        |
|.* +     .       |
|  * +            |
| .E+ .           |
| .o              |
+-----------------+
```

###次に、「catコマンド」で表示されたssh公開鍵の値をコピー
「catコマンド」を実行することで、そのファイルの具体的な内容をターミナル上で確認できる

```
[ec2-user@ip-***-**-**-*** ~]$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2E......
```

次に、catコマンドで表示された公開鍵をGitHubに登録する。
以下のURLにアクセス

https://github.com/settings/keys

「Title」を記入
「Key」に先ほどの公開鍵をペースト
「ADD SSH Key」を押して保存

GitHubに鍵を登録できたら、ssh接続できるか以下のコマンドで確認
※ 途中でこのまま続けるかどうかYes/Noで聞かれることがあるが、「Yes」で進む

```
[ec2-user@ip-***-**-**-*** ~]$ ssh -T git@github.com
Hi <Githubユーザー名>! You've successfully authenticated, but GitHub does not provide shell access.
```

「Permission denied (publickey).」と表示された場合は、
ssh鍵の設定が間違っているので、再度作業を確認する。

##アプリケーションサーバーの設定
「アプリケーションサーバー」とは、ブラウザからの「リクエスト」を受け付け
Railsアプリケーションを実際に動作させるソフトウェアのこと

EC2サーバー上でもアプリケーションサーバを動かす必要がある。
そのために必要なツールが**``Unicorn``**

「Unicorn」とは、全世界に公開されるサーバ上で良く利用されるアプリケーションサーバー。rails sコマンドの代わりに「unicorn_railsコマンド」で起動することができる。

##Unicornをインストール
Gemfileの一番下に以下の内容を追記し、bundle install
※group :production do〜end」がすでに存在している場合は、その中に追記

```
group :production do
  gem 'unicorn', '5.4.1'
end
```

##「unicorn.rb」を作成し編集する
※以下の作業は「masterブランチ」で作業する

「config/unicorn.rb」を作成し、内容を以下のように編集

```config/unicorn.rb
#サーバ上でのアプリケーションコードが設置されているディレクトリを変数に入れておく
app_path = File.expand_path('../../', __FILE__)

#アプリケーションサーバの性能を決定する
#リクエストを受け付けレスポンスを生成するworker(ワーカー)の数を決める
worker_processes 1

#アプリケーションの設置されているディレクトリを指定
#UnicornがRailsのコードを動かす際、ルーティングなど実際に参照するファイルを探すディレクトリを指定する
working_directory app_path

#Unicornの起動に必要なファイルの設置場所を指定
#Unicornは、起動する際にプロセスidが書かれたファイルを生成する。その場所を指定。
pid "#{app_path}/tmp/pids/unicorn.pid"

#ポート番号を指定
#どのポート番号のリクエストを受け付けることにするかを決定する。今回は、3000番ポートを指定。
listen 3000

#エラーのログを記録するファイルを指定
stderr_path "#{app_path}/log/unicorn.stderr.log"

#通常のログを記録するファイルを指定
stdout_path "#{app_path}/log/unicorn.stdout.log"

#Railsアプリケーションの応答を待つ上限時間を設定
timeout 60

#以下は応用的な設定なので説明は割愛

preload_app true
GC.respond_to?(:copy_on_write_friendly=) && GC.copy_on_write_friendly = true

check_client_connection false

run_once = true

before_fork do |server, worker|
  defined?(ActiveRecord::Base) &&
    ActiveRecord::Base.connection.disconnect!

  if run_once
    run_once = false # prevent from firing again
  end

  old_pid = "#{server.config[:pid]}.oldbin"
  if File.exist?(old_pid) && server.pid != old_pid
    begin
      sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
      Process.kill(sig, File.read(old_pid).to_i)
    rescue Errno::ENOENT, Errno::ESRCH => e
      logger.error e
    end
  end
end

after_fork do |_server, _worker|
  defined?(ActiveRecord::Base) && ActiveRecord::Base.establish_connection
end
```

##編集内容をリモートリポジトリに反映
リモートリポジトリに「commit→push」
GitHubのリモートリポジトリに反映ができたら、ここまでのローカルの全内容をEC2に反映させる。
※別にブランチを切っている場合は、masterブランチにmergeしてから以下のコマンドを実行

```
#mkdirコマンドで新たにディレクトリを作成
[ec2-user@ip-***-**-**-*** ~]$ sudo mkdir /var/www/

#作成したwwwディレクトリの権限をec2-userに変更
[ec2-user@ip-***-**-**-*** ~]$ sudo chown ec2-user /var/www/
```

次に、GitHubから「リポジトリURL」を取得し、クローンする。
緑色の「Code」を押すとURLがコピーできる。
[![Image from Gyazo](https://i.gyazo.com/dca26e4c60beb1b05c695e10462bf71a.png)](https://gyazo.com/dca26e4c60beb1b05c695e10462bf71a)

URLがコピーできたら、コードをクローン

```
[ec2-user@ip-***-**-**-*** ~]$ cd /var/www/
[ec2-user@ip-***-**-**-*** www]$ git clone コピーしたURLを貼り付ける
```

上記の入力でエラーがでなければ成功。


##本番環境での設定
現状動かしているEC2のインスタンスではコンピューターの能力が足りず、
Gemのインストール時などにエラーが発生する可能性がある。
具体的には、コンピューターの処理能力に関係するメモリというものが足りない。
これは、無料で動かせるインスタンスの限界であるため仕方ないこと..

そこで、今後の設定を行う前に「Swapファイル」というメモリを増強する処理を行います。

「Swapファイル」とは、メモリの容量を一時的に増やすために準備されるファイルのこと。
EC2はデフォルトではSwapファイルを用意していないため、これを準備することでメモリ不足の処理エラーを防ぐ。

##Swapファイルの領域を広げる
EC2にssh接続をしてホームディレクトリに移動
ターミナル（EC2内）で実行

```
[ec2-user@ip-***-**-**-*** ~]$ cd 
```

順に下記のコマンドを実行

```
[ec2-user@ip-***-**-**-*** ~]$ sudo dd if=/dev/zero of=/swapfile1 bs=1M count=512

# しばらく待って、以下のように表示されれば成功
512+0 レコード入力
512+0 レコード出力
536870912 バイト (537 MB) コピーされました、 7.35077 秒、 73.0 MB/秒
```

```
[ec2-user@ip-***-**-**-*** ~]$ sudo chmod 600 /swapfile1
```

```
[ec2-user@ip-***-**-**-*** ~]$ sudo mkswap /swapfile1

# 以下のように表示されれば成功
スワップ空間バージョン1を設定します、サイズ = 524284 KiB
ラベルはありません, UUID=74a961ba-7a33-4c18-b1cd-9779bcda8ab1
```

```
[ec2-user@ip-***-**-**-*** ~]$ sudo swapon /swapfile1
```

```
[ec2-user@ip-***-**-**-*** ~]$ sudo sh -c 'echo "/swapfile1  none        swap    sw              0   0" >> /etc/fstab'
```
これで、Swapファイルの領域を確保完了

##EC2内でgemをインストール
EC2にクローンしたアプリケーションを起動するために必要なgemを以下のコマンドでインストール

ターミナル（EC2内）で実行

```
# クローンしたディレクトリに移動
[ec2-user@ip-***-**-**-*** www]$ cd  /var/www/開発中のアプリケーション

# rubyのバージョンを確認
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
```

※「ruby 2.6.5 ...」となっていれば成功です。そうでない場合は、
もともと用意されているRubyが利用されているので、Rubyのインストールが成功しているか確認する。

次に、本番環境でgemを管理するためのbundlerをインストールする。
まずは、ローカルで開発してきたアプリケーションでどのバージョンのbundlerが使われていたのか確認。

ターミナル（ローカル）で実行

```
# 開発中のアプリケーションのディレクトリで実行

% bundler -v
Bundler version 2.1.4 ←例
```

ローカルと同じバージョンのbundlerをEC2側にも導入。
上記の場合では「bundler 2.1.4」のバージョンを導入してbundle installを実行。

ターミナル（EC2内）で実行

```
# 「2.1.4」の箇所は、ローカルで確認したbundlerのバージョンを導入
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ gem install bundler -v 2.1.4

# 以下のコマンドは、処理に数分以上かかる場合があります
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ bundle install
```

##環境変数を設定
環境変数は、Railsからは「ENV['<環境変数名>']」という記述でその値を利用できる。
今回は「SECRET_KEY_BASE」という環境変数を指定。

secret_key_base」とは、Cookieの暗号化に用いられる文字列のこと。
Railsアプリケーションを動作させる際は必ず用意する必要がある。
また、外部に漏らしてはいけない値であるため、こちらも環境変数から参照する。

まずは、以下のコマンドでsecret_key_baseを作成

ターミナル（EC2内）で実行

```
# 「2.1.4」の箇所は、ローカルで確認したbundlerのバージョンを導入
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ rake secret
69619d9a75b78f2e1c87ec5e07541b42f23efeb6a54e97da3723de06fe74af29d5718adff77d2b04b2805d3a1e143fa61baacfbf4ca2c6fcc608cff8d5a28e8d
```

※表示された英数の羅列はすべてメモアプリなどに控えておく

次に、EC2内に環境変数を設定する。
環境変数は「/etc/environment」というファイルに保存する。
環境変数の書き込みにはvimコマンドを使用。その際、「sudo」というオプションを使う。

「sudo」とは、「全部の権限を持った上でコマンドを実行する」という役割のオプションのこと。
「/etc以下のファイル」は強い権限がないと書き込み・保存ができないため、コマンドの頭に「sudo」をつける。

ターミナル（EC2内）で実行

```
# 「2.1.4」の箇所は、ローカルで確認したbundlerのバージョンを導入
[ec2-user@ip-***-**-**-*** ~]$ sudo vim /etc/environment
```

「i」と打ち込み入力モードに。その後、下記の通り記述する。

```
#　データベースのrootユーザーのパスワードを入力（下記のリンクから記事を参照できます）

DATABASE_PASSWORD='データベースのrootユーザーのパスワード'
SECRET_KEY_BASE='さきほど作成したsecret_key_base'
```

※ [rootユーザーの設定](https://qiita.com/maca12vel/items/b0f245e8c0e63a3bc295)
AWSのアカウント作成をお読みください。

入力を終えたら「escキー」→「:wq」の順で実行し、保存する。
設定した環境変数を反映させるために、一度本番環境をログアウトする。

ターミナル（EC2内）で実行

```
# 「2.1.4」の箇所は、ローカルで確認したbundlerのバージョンを導入
[ec2-user@ip-***-**-**-*** ~]$ exit
logout
Connection to 52.xx.xx.xx closed.
```

次は、いま設定した環境変数がしっかり反映されているか確認する。
以下のコマンドで再度EC2に接続。

ターミナル（ローカル）

```
$ ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
```

接続し直したら、「envコマンド」と「grepコマンド」を組み合わせて、
さきほど設定した環境変数が適用されているか確認する。

envコマンド：設定されている環境変数を表示するためのコマンド
grepコマンド：環境変数などを検索するときに使うコマンド
使い方は「grep （検索対象）」となる。

ターミナル（EC2内）で実行

```
# 「2.1.4」の箇所は、ローカルで確認したbundlerのバージョンを導入
[ec2-user@ip-***-**-**-*** ~]$ env | grep SECRET_KEY_BASE
SECRET_KEY_BASE='secret_key_base'

[ec2-user@ip-***-**-**-*** ~]$ env | grep DATABASE_PASSWORD
DATABASE_PASSWORD='データベースのrootユーザーのパスワード'
```

##ポートを解放
立ち上げたばかりのEC2インスタンスはsshでアクセスすることはできるが、
HTTPなどの他の通信方法では一切つながらないようになっている。
そのためサーバーとして利用するEC2インスタンスは事前にHTTPがつながるように「ポート」を開放する必要がある。
さきほど、config/unicorn.rb内に「listen 3000」と記述したが、
これは「Railsのサーバを3000番ポートで起動する」ということを意味する。

ポートの設定をするためには、EC2の「セキュリティグループ」という設定を変更する必要がある。

###セキュリティグループのポートを設定

EC2インスタンス一覧画面から対象のインスタンスを選択し、
図中の右下にある「セキュリティグループ」のリンク（図中では「launch-wizard-2」）をクリック
![Image from Gyazo](https://i.gyazo.com/cef10db71b1cb250b5fcc8851bc46d1b.png)](https://gyazo.com/cef10db71b1cb250b5fcc8851bc46d1b)

次に「インバウンド」タブの中の「インバウンドルールを編集」をクリック
[![Image from Gyazo](https://i.gyazo.com/51399017df126a2a5f4854edb5dc6acb.png)](https://gyazo.com/51399017df126a2a5f4854edb5dc6acb)

画面遷移後は「ルールを追加」をクリックして下記のように編集
タイプ：カスタムTCP
プロトコル：TCP
ポート範囲：3000
送信元：カスタム/0.0.0.0/0
[![Image from Gyazo](https://i.gyazo.com/78386ef4fd5a1823b5836a83a81c141e.png)](https://gyazo.com/78386ef4fd5a1823b5836a83a81c141e)

設定後、「ルールを保存」をクリック。ポートの開放は以上。

##本番環境でRailsを起動
本番環境でRailsを起動するには「unicorn_railsコマンド」を使う。

まず、VSCodeで「database.yml」の本番環境の設定を編集する。
本番環境のmysqlの設定に合わせるため、ローカルのdatabase.ymlを以下のように編集。

```config/database.yml（ローカル）
production:
  <<: *default
  database:（※こちらは編集しない）
  username: root
  password: <%= ENV['DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock
```

次に、編集を「commit→push」

次は、GitHubの内容をEC2に反映
以下のコマンドをターミナル（EC2内)で実行
※別にブランチを切っている場合は、masterブランチにmergeしてから以下のコマンドを実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ git pull origin master
```

次は、EC2内でデータベースを作成する。
「RAILS_ENV=production」というオプションがつく。
RAILS_ENV=production：本番環境でコマンド実行する時につくオプションのこと

ターミナル（EC2内)で実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ rails db:migrate RAILS_ENV=production
```
※ もしここで「Mysql2::Error: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'」というエラーが起こった場合、データベースが起動していない可能性がある。
「sudo systemctl start mariadb」というコマンドをターミナルから打ち込み、mysqlの起動を試す。

ここまでできたら、Railsを起動する。

ターミナル（EC2内)で実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ cd /var/www/[リポジトリ]
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D
```

ブラウザで http://＜Elastic IP＞:3000/ にアクセスして、サイトが表示されているか確認する。
※接続時、＜Elastic IP＞の＜＞は入力不要

ブラウザで確認すると、ビューが崩れたまま。
エラーメッセージ（We're sorry, but something went wrong.）が表示される場合もある。

これではまずいので、「アセットファイル」を整理する。

アセットファイル：画像・CSS・JavaScript等を管理しているファイルのこと。
このアセットファイルを圧縮し、そのデータを転送する処理を「コンパイル」と言う。
この作業を行わないと、本番環境でCSSが反映されずにビューが崩れてしまったり、
エラーでブラウザが表示されない、などの問題が生じてしまう。

###アセットファイルをコンパイル

ターミナル（EC2内)で実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ rails assets:precompile RAILS_ENV=production
```

ここまで終えたら再度Railsを起動させたが、すでにサーバーは立ち上がっているので、Railsを再起動する必要がある。

###以下の手順で、本番環境のRailsを再起動
まず、「Unicornのプロセス」を確認。
ターミナルからプロセスを確認するには「psコマンド」を利用する。
その後、「killコマンド」でプロセスを終了させる。

psコマンド：現在動いているプロセスを確認するためのコマンドのこと。
killコマンド：現在動いているプロセスを停止させるためのコマンドのこと。

ターミナル（EC2内)で実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ ps aux | grep unicorn
...

すると、以下のようにプロセスが表示されるはず。

```bash:ターミナル
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」の右隣の数字がプロセスid（PID）
「unicorn_rails master」と表示されているプロセスがUnicornのプロセス本体
この時のプロセスidは「17877」

ターミナル（EC2内)で実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ kill <確認したunicorn rails masterのプロセスid> ←今回だと 17878
```

実行したプロセスを再度表示し、終了できていることを確認する。

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ ps aux | grep unicorn
...
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn
```

実行結果が上記のようになっていれば、Unicornの停止が完了。
※ プロセスが1つだけ残っているのは、「ps aux | grep unicorn」コマンドのプロセス
「unicornのプロセスを検索ために使った ”ps aux | grep unicorn” もカウントされている」ということになる。

###最後に、Railsを再起動するコマンドを実行
「RAILS_SERVE_STATIC_FILES=1」は、Railsがコンパイルされたアセットを見つけられるように指定する役割がある。

ターミナル（EC2内)で実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
```

ブラウザで http://＜Elastic IP＞:3000/ にアクセスして、サイトが表示されているか確認する。
※接続時、＜Elastic IP＞の＜＞は入力不要

---

##Railsの起動がうまくできなかった時
unicorn_railsを実行した際に
「master failed to start, check stderr log for details」
と出た場合、unicornのエラーログを確認する必要がある。

ログファイルを見る際に「lessコマンド」というものを使う

lessコマンド：ファイルの中身を確認できるコマンド。「catコマンド」も同様の役割がある。

ターミナル（EC2内)で実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ less log/unicorn.stderr.log
I, [2016-12-21T04:01:19.135154 #18813]  INFO -- : Refreshing Gem list
I, [2016-12-21T04:01:20.732521 #18813]  INFO -- : listening on addr=0.0.0.0:3000 fd=10
E, [2016-12-21T04:01:20.734067 #18813] Mysql2::Error::ConnectionError: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
/var/www/furima/shared/bundle/ruby/2.6.0/gems/mysql2-0.5.3/lib/mysql2/client.rb:90:in `connect'
/var/www/furima/shared/bundle/ruby/2.6.0/gems/mysql2-0.5.3/lib/mysql2/client.rb:90:in `initialize'
/var/www/furima/shared/bundle/ruby/2.6.0/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/mysql2_adapter.rb:24:in `new'
/var/www/furima/shared/bundle/ruby/2.6.0/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/mysql2_adapter.rb:24:in `mysql2_connection'
/var/www/furima/shared/bundle/ruby/2.6.0/gems/activerecord-6.0.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:889:in `new_connection'
```

※ログファイルは「一番下から最新のログ」が表示される。
”「shiftキー」＋「G」”を実行すると、一番下まで一瞬で移動できる。この中からエラー文を探す。

---

##「We’re sorry, but 〜」と表示されている時
まずは「production.log」を確認する。

production.log：サーバーログを記録する場所で、「EC2内での出来事を記録している場所」のこと

ターミナル（EC2内)で実行

```
[ec2-user@ip-***-**-**-*** <リポジトリ名>]$ less log/production.log

（production.logの表示）
```

※ログファイルは「一番下から最新のログ」が表示される。
”「shiftキー」＋「G」”を実行すると、一番下まで一瞬で移動できる。この中からエラー文を探す。

####tail -fコマンドを使う
tail -fコマンド：最新のログを10行分だけ表示してくれるコマンドのこと。
ログを見やすく確認できるツールなのでなるべく使うようにする。

---

以上です。お疲れ様でした。

続きは → [こちら](https://qiita.com/maca12vel/items/35f9fb73bb21cb4869fb)