EC2インスタンスにRails + MySQL環境構築

# はじめに

`AWS`の`EC2インスタンス`立ち上げたところからのサーバー構築手順です。

・設定用のツールをインストール
・Node.jsをインストール
・Yarnをインストール
・rbenvとruby-buildをインストール
・Rubyをインストール
・MariaDBをインストール(サーバーにDB設定する場合)
・Githubとの接続
・Unicornをインストール
・Githubからコードをクローン
・gemをインストール
・環境変数の設定
・アセットファイルをコンパイル
・本番環境でRailsを起動

ここまではアプリケーションサーバー構築。
WEBサーバー構築は以下。
[EC2サーバーにRails + Nginx](https://qiita.com/yamato1491038/items/36d49f15edb52353ad91)


# 設定用のツールをインストール
`yum`というコマンドを使ってこのサーバに元々あるプログラムをアップデートします。

```
$ sudo yum -y update
```

環境構築に必要なパッケージを諸々インストール。（長いコマンド）

```
$ sudo yum  -y install git make gcc-c++ patch libyaml-devel libffi-devel libicu-devel zlib-devel readline-devel libxml2-devel libxslt-devel ImageMagick ImageMagick-devel openssl-devel libcurl libcurl-devel curl
```
# Node.jsをインストール
サーバーサイドで動く`JavaScript`のパッケージです。

```
$ sudo curl -sL https://rpm.nodesource.com/setup_10.x | sudo bash -
$ sudo yum -y install nodejs
```

# Yarnをインストール

`Rails`に搭載されているJavaScriptのパッケージを管理するためのパッケージマネージャです。

```
$ sudo yum -y install wget
$ sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
$ sudo yum -y install yarn
```

# rbenvとruby-buildをインストール

`rbenv`と`ruby-build`は、`Ruby`のバージョンを管理する際に組み合わせて使うツールになります。これらは`Ruby`をインストールする前に、インストールする必要があります。
`ruby-build`は`rbenv`のプラグインであり、`ruby-build`によって`Ruby`の様々なバージョン(2.0.0など)をインストールすることができます。
`rbenv`を使用することで`ruby`のバージョンを切り替えることできます。

```
#rbenvのインストール
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv

#パスを通す(どのディレクトリからもアプリケーションを呼び出せる状態にする)
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile

#rbenvを呼び出すための記述
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile

#.bash_profileの読み込み
$ source .bash_profile

#ruby-buildのインストール
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

#rehashを行う
$ rbenv rehash
```

# Rubyをインストール

`Ruby`のインストールには時間がかかります。

```
$ rbenv install 2.6.5
$ rbenv global 2.6.5 #EC2インスタンス内で使用するRubyのバージョンを決める
$ rbenv rehash  #rehashを行う
$ ruby -v # バージョンを確認
```


※`AWS RDS`を使用する場合は`MariaDB関連操作`は不要。
# MariaDBをインストール(サーバーにDB設定する場合)
`Amazon Linux 2`を利用している場合、`MariaDB`は `yum` コマンドからインストールすることができます。

```
$ sudo yum -y install mysql56-server mysql56-devel mysql56 mariadb-server mysql-devel
```
○○○利用できませんと表示されますが問題ありません。

# データベースを起動
データベースを起動するために`systemctl`コマンドを利用します。これは、`Amazon Linux`や`CentOS`に含まれているもので、インストールしたソフトウェアの起動を一括して行えるツールです。

```
$ sudo systemctl start mariadb
$ sudo systemctl status mariadb #起動できたか確認
```
# データベースのrootパスワードの設定
`yum` でインストールした`MariaDB`には、デフォルトで root というユーザーでアクセス出来るようになっていますが、パスワードは設定されていません。パスワードを設定していきます。

```
$ sudo /usr/bin/mysql_secure_installation
```

対話形式でパスワードを設定します。

# データベースへの接続確認

```
$ mysql -u root -p
```
パスワードを入力するように表示されるので、先程設定したパスワードを入力して、Enterしてください。

# Githubとの接続
EC2サーバのSSH鍵ペアを作成

```
$ 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              |
+-----------------+
```
全て何も入力せずにEnterキーで進んでください。

生成されたSSH公開鍵を表示し、値をコピーします。

```
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2E......
```

catで表示させた公開鍵を、Githubにアクセスして登録していきます。
https://github.com/settings/keys

①Titleは自由に記入
②Keyに公開鍵をペースト
③`Add SSH Key`を押して保存

Githubに鍵を登録できたら、SSH接続できるか以下のコマンドで確認

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

Permission denied (publickey). と表示された場合は、SSH鍵の設定が間違っているので、作業を確認してください。


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

# Unicornをインストール

ローカル環境のGemfile を編集

```rb
group :production do
  gem 'unicorn', '5.4.1'
end
```
ローカルのターミナルで

```
% bundle install
```
# config/unicorn.rbを作成し、内容を以下のように編集

```rb

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

#アプリケーションサーバの性能を決定する
worker_processes 1

#アプリケーションの設置されているディレクトリを指定
working_directory app_path

#Unicornの起動に必要なファイルの設置場所を指定
pid "#{app_path}/tmp/pids/unicorn.pid"

#ポート番号を指定
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
```


# Githubからコードをクローン
EC2サーバーにSSH接続後に以下の操作

```
#mkdirコマンドで新たにディレクトリを作成
$ sudo mkdir /var/www/

#作成したwwwディレクトリの権限をec2-userに変更
$ sudo chown ec2-user /var/www/

#移動
$ cd /var/www/

#Githubから「リポジトリURL」を取得しクローンします
$ git clone https://github.com/<ユーザー名>/<リポジトリ名>.git
```

# Swap(スワップ)領域作成
Swap領域は、メモリが使い切られそうになった時にメモリの容量を一時的に増やすために準備されるファイルです。

EC2はデフォルトではSwap領域を用意していないため、これを準備することでメモリ不足の処理エラーを防ぎます。

```
$ cd
$ sudo dd if=/dev/zero of=/swapfile1 bs=1M count=512
# しばらく待って、以下のように表示されれば成功
512+0 レコード入力
512+0 レコード出力
536870912 バイト (537 MB) コピーされました、 7.35077 秒、 73.0 MB/秒

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

$ sudo swapon /swapfile1

#右へ長いコマンドです
$ sudo sh -c 'echo "/swapfile1  none        swap    sw              0   0" >> /etc/fstab'
```

# gemをインストール
rbenvでインストールされたRubyが使われているかチェック

```
$ cd  /var/www/<アプリ名>
$ ruby -v
ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-linux]
```
本番環境でgemを管理するためのbundlerをインストールして、bundle installを実行

ローカル環境でバージョン確認。

```
#ローカル環境　アプリのディレクトリで以下を実行
% bundler -v
Bundler version 2.1.4
```
ローカルと同じバージョンをEC2サーバー上で以下のコマンド

```
# ローカルで確認したbundlerのバージョンを導入する
$ gem install bundler -v 2.1.4

$ bundle install
```

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

```
$ rake secret
69619d9a75b78f2e1c87ec5e07541b42f23efeb6a54e97da3723de06fe74af29d5718adff77d2b04b2805d3a1e143fa61baacfbf4ca2c6fcc608cff8d5a28e8d
```
この長い英数の羅列は、この後利用するのでコピーしておきます。

環境変数は `/etc/environment` というファイルに保存することで、サーバ全体に適用されます。

```
$ sudo vim /etc/environment
```

```rb

#前章で設定したデータベースのrootユーザーのパスワードを入力
DATABASE_PASSWORD='データベースのrootユーザーのパスワード'
SECRET_KEY_BASE='先程コピーしたsecret_key_base'
```
書き込みができたら esc(エスケープキー)を押下後、`:wq`と入力して内容を保存します。
保存できたら環境変数を適用するために一旦ログアウト。

```
$ exit
logout
Connection to 52.xx.xx.xx closed.
```
再度ログイン。

```
$ ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
```
環境変数が適用されているか確認

```
$ env | grep SECRET_KEY_BASE
SECRET_KEY_BASE='secret_key_base'

$ env | grep DATABASE_PASSWORD
DATABASE_PASSWORD='データベースのrootユーザーのパスワード'
```
# ポートを開放
`config/unicorn.rb` に `listen 3000` と記述しましたが、これはRailsのサーバを3000番ポートで起動するということを意味します。

EC2インスタンスの`セキュリティグループ`を編集し`カスタムTCP`でポート3000を許可してください。

# database.ymlの本番環境の設定
`config/database.yml（ローカル）`を以下のように設定。

```rb

  <<: *default
  database: ~~~（それぞれのアプリによって異なる）
  username: root
  password: <%= ENV['DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock
```
※`RDS`など使用の場合はまた異なります。

ローカルでの編集をコミットして、GitHubにプッシュし、EC2へ再度クローンします。

```
$ git pull origin master
```

# データベースを作成しマイグレーションを実行
EC2サーバー上で以下のコマンド。

```
$ rails db:create RAILS_ENV=production
Created database '<データベース名>'

$ rails db:migrate RAILS_ENV=production
```
もしデータベースが起動していないときは

```
sudo systemctl start mariadb
```

# アセットファイルをコンパイル
本番モードでは、事前にアセットをコンパイルする必要があります。

```
$ rails assets:precompile RAILS_ENV=production
```


# 本番環境でRailsを起動
unicorn のgemをインストールしていると `unicorn_rails` というコマンドが使えるようになっています.
ローカルでいう`rails s`にあたります。

Unicornのプロセスを確認

```
$ 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`コマンドで停止してください。

```
$ kill <確認したunicorn rails masterのPID>
```
unicornを起動

```
$ cd /var/www/[リポジトリ]
$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
```
`RAILS_SERVE_STATIC_FILES=1`は、コンパイルされたアセットをRailsが見つけられるような指定です。





# ブラウザで確認
http://＜Elastic IP＞:3000/で正常に表示されれば成功です。

# うまく表示されない場合
エラーが起こっているのでログを確認。

```
$tail -f /var/www/<アプリ名>/log/production.log
```
または/var/www/<リポジトリ名>/log/unicorn.stderr.logをlessまたはcatコマンドで確認。

設定は以上です。