AWSでアプリをデプロイする方法(手動デプロイ編)

# データベース作成後、Railsを使用した手動デプロイの方法を紹介します！(学習記録):mount_fuji:

#### EC2上でRailsを起動するための設定
まず、アプリケーションのコードをGitHubからEC2サーバへクローンします。デプロイできるIPアドレスを持ったEC2サーバー上でアプリケーションを動かすためです。
EC2インスタンスからGitHubにアクセスするためには、作成したEC2インスタンスのssh公開鍵をGitHubに登録する必要があります。
ssh鍵をGitHubに登録すると、GitHubはそれを認証に利用し、コードのクローンを許可してくれるようになります。

#### EC2サーバーのssh鍵のペアを作成し、GitHubにssh鍵を登録しましょう

```
# EC2内で実行
[ec2-user@<自身のElasticIP> ~]$ ssh-keygen -t rsa -b 4096
# 途中で「passphrase」など3段階ほど入力を求められることがありますが、すべて何も入力せずにEnterキーを押して進んでください。
```

#### ssh公開鍵の値を確認し、GitHubに登録しましょう

```
# catコマンドで、公開鍵が含まれているファイルid_rsa.pubの中身をターミナル上に表示します。
[ec2-user@<自身のElasticIP> ~]$ cat ~/.ssh/id_rsa.pub
# そして、以下のように表示される公開鍵の情報をすべて（「ssh-rsa」から「末尾の文字」まで）コピーします
```
##### 次に、コピーした公開鍵をGitHubに登録します。
GitHubのSSH and GPG keysという項目をクリックします！その後、New SSH keyという欄をクリックして公開鍵のタイトルを設定し、コピーした公開鍵を貼り付けましょう。入力ができたら、「Add SSH key」をクリックして公開鍵を保存します

```
# EC2内で実行
[ec2-user@<自身のElasticIP> ~]$ ssh -T git@github.com
# 次のように表示されれば成功　# 途中「Yes/No」または「y/n」などの選択肢で聞かれることがあります。その場合は「Yes」または「y」などの「許容」を意味する入力をし、Enterキーを押下して進んでください。
Hi <Githubユーザー名>! You've successfully authenticated, but GitHub does not provide shell access.
```

#### アプリケーションサーバーの設定
「アプリケーションサーバー」とは、ブラウザからの「リクエスト」を受け付けRailsアプリケーションを実際に動作させるソフトウェアのことです。
##### Unicorn
「Unicorn」とは、全世界に公開されるサーバ上で良く利用されるアプリケーションサーバーです。rails sコマンドの代わりに「unicorn_railsコマンド」で起動することができます。この後、EC2サーバにssh接続しUnicornを起動することで全世界からアクセスできるようにします。
##### プロセス
「プロセス」とは、PC上で動くすべてのプログラムの実行時の単位です。ここで言うプログラムとは、ブラウザや音楽再生ソフト、ExcelといったGUIや、Rubyなどのスクリプト言語の実行などが含まれます。

#### Unicornの設定
Gemfileのgroup :production do〜end内に内容を追記しましょう。

```
# Gemfile
group :production do
  gem 'unicorn', '5.4.1'
end
# bundle installをする
% bundle install
```

##### unicorn.rbを作成
以下の作業は「masterブランチ」で作業しましょう。
「config/unicorn.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
```

##### worker(ワーカー)
「worker」とは、分裂したUnicornの全プロセスのことです。プロセスを分裂させることで、リクエストに対してのレスポンスを高速にできます。後述するworker_processesという設定項目で、workerの数を決定します。
##### 編集内容をリモートリポジトリに反映
ここまで編集できたら、リモートリポジトリに「commit→push」しましょう。GitHubのリモートリポジトリに反映ができたら、ここまでのローカルの全内容をEC2に反映します。
##### EC2にローカルの全内容を反映
```
# EC2内で実行
#mkdirコマンドで新たにディレクトリを作成
[ec2-user@<自身のElasticIP> ~]$ sudo mkdir /var/www/

#作成したwwwディレクトリの権限をec2-userに変更
[ec2-user@<自身のElasticIP> ~]$ sudo chown ec2-user /var/www/

# 次に、GitHubから「リポジトリURL」を取得し、クローンします。デプロイするアプリケーションのGitHubを開きましょう。緑色で「Code」と表示されているボタンをクリックして、URLをコピーします。
[ec2-user@<自身のElasticIP> ~]$ cd /var/www/
[ec2-user@<自身のElasticIP> www]$ git clone コピーしたURLを貼り付ける
```
ここまでで、アプリケーションのコードをEC2にクローンすることができました。続いて、サービスを公開するための設定を行なっていきます。
##### EC2の能力を拡張
現状動かしているEC2のインスタンスではコンピューターの能力が足りず、Gemのインストール時などにエラーが発生する可能性があります。具体的には、コンピューターの処理能力に関係するメモリというものが足りません。これは、無料で動かせるインスタンスの限界であるため仕方ありません。そこで、今後の設定を行う前に「Swapファイル」というメモリを増強する処理を行います。
##### Swapファイル
「Swapファイル」とは、メモリの容量を一時的に増やすために準備されるファイルのことです。コンピューターが処理を行う際、メモリと呼ばれる場所に処理内容が一時的に記録されます。メモリは容量が決まっており、容量を超えてしまうとエラーで処理が止まってしまいます。
##### まずは、EC2にssh接続をしてホームディレクトリに移動します。
```
# ホームディレクトリに移動
[ec2-user@<自身のElasticIP> ~]$ cd

# 処理に時間がかかる可能性があるコマンドです
[ec2-user@<自身のElasticIP> ~]$ sudo dd if=/dev/zero of=/swapfile1 bs=1M count=512

[ec2-user@<自身のElasticIP> ~]$ sudo chmod 600 /swapfile1

[ec2-user@<自身のElasticIP> ~]$ sudo mkswap /swapfile1

[ec2-user@<自身のElasticIP> ~]$ sudo swapon /swapfile1
	
[ec2-user@<自身のElasticIP> ~]$ sudo sh -c 'echo "/swapfile1  none        swap    sw              0   0" >> /etc/fstab'
```
これで、Swapファイルの領域を確保することができました。

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

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

# rubyのバージョンを確認
[ec2-user@<自身のElasticIP> <リポジトリ名>]$ ruby -v
```
次に、本番環境でgemを管理するためのbundlerをインストールします。まずは、ローカルで開発してきたアプリケーションでどのバージョンのbundlerが使われていたのか確認します。

```
# 開発中のアプリケーションのディレクトリで実行
% bundler -v
Bundler version 自身のbundlerのバージョン
```

```
# EC2内で実行
[ec2-user@<自身のElasticIP> <リポジトリ名>]$ gem install bundler -v 自身のバージョンを記述

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

#### 環境変数の設定
データベースのパスワードなどセキュリティのためにGitHubにアップロードすることができない情報は「環境変数」を利用して設定します。環境変数は、Railsからは「ENV['<環境変数名>']」という記述でその値を利用できます。今回は「SECRET_KEY_BASE」という環境変数を指定します。 
##### secret_key_base
「secret_key_base」とは、Cookieの暗号化に用いられる文字列です。Railsアプリケーションを動作させる際は必ず用意する必要があります。また、外部に漏らしてはいけない値であるため、こちらも環境変数から参照します。

##### secret_key_baseを作成しましょう

```
[ec2-user@<自身のElasticIP> <リポジトリ名>]$ rake secret
# 表示された英数の羅列はすべてメモアプリなどに控えておきましょう。
```
次に、EC2内に環境変数を設定しましょう。環境変数は「/etc/environment」というファイルに保存します。環境変数の書き込みにはvimコマンドを使用しましょう。その際、「sudo」というオプションを使います。

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

##### 環境変数を設定しましょう

```
# コマンドを実行してsecret_key_baseを環境変数に設定しましょう。
[ec2-user@<自身のElasticIP> ~]$ sudo vim /etc/environment

# /etc/environment
#設定したデータベースのrootユーザーのパスワードを入力
DATABASE_PASSWORD='データベースのrootユーザーのパスワード'
SECRET_KEY_BASE='さきほど作成したsecret_key_base'

# ダウンロードしたCSVファイルを参考に値を入力
AWS_ACCESS_KEY_ID='ここにCSVファイルのAccess key IDの値をコピー'
AWS_SECRET_ACCESS_KEY='ここにCSVファイルのSecret access keyの値をコピー'
```

##### 環境変数を反映させましょう

```
# 設定した環境変数を反映させるために、一度本番環境をログアウトします。
[ec2-user@<自身のElasticIP> ~]$ exit

# exitでログアウトするので、以下のコマンドで再度EC2に接続します。
$ ssh -i [ダウンロードした鍵の名前].pem ec2-user@[作成したEC2インスタンスと紐付けたElastic IP]
```

#### ポートを解放しよう
立ち上げたばかりのEC2インスタンスはsshでアクセスすることはできますが、HTTPなどの他の通信方法では一切つながらないようになっています。そのため、サーバーとして利用するEC2インスタンスは事前にHTTPがつながるように「ポート」を開放する必要があります。ポートの設定をするためには、EC2の「セキュリティグループ」という設定を変更する必要があります。

##### セキュリティーグループ
「セキュリティグループ」とは、EC2サーバが属するまとまりのようなもので、複数のEC2インスタンスのネットワーク設定を一括で行うためのものです。
##### セキュリティーグループのポートを設定しよう
まず、EC2インスタンス一覧画面から、対象のインスタンスを選択し、「セキュリティ」のタブを開きます。次に、「セキュリティグループ」のリンクをクリック！すると、インスタンスの属するセキュリティグループの設定画面に移動するので、「インバウンド」タブの中の「編集」をクリックします。ページが切り替わるので、「インバウンドルールを編集」をクリックし、以下の通りに設定しましょう。
ページ遷移後、「ルールを追加」をクリックして編集します！例えば、タイプ：カスタムTCP,プロトコル：TCP,ポート範囲：3000,送信もと：カスタム/0.0.0.0/0などと編集します！「0.0.0.0」は「すべてのアクセスを許可する」という意味です。設定後、「ルールを保存」をクリックしましょう。ポートの開放は以上です。

#### 本番環境でRailsを起動させる
本番環境でRailsを起動するには「unicorn_railsコマンド」を使います。まず、本番環境の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-user@<自身のElasticIP> <リポジトリ名>] git pull origin master
```
次は、EC2内でデータベースを作成するのですが、「RAILS_ENV=production」というオプションがつきます。

##### RAILS_ENV=production
「RAILS_ENV=production」とは、本番環境でコマンド実行する時につくオプションです。
実行しようとしているコマンドは、「RAILSのENV（環境）がproduction（本番環境）ですよ」という意味です。

```
# 以下のコマンドを順に実行しましょう
[ec2-user@<自身のElasticIP> <リポジトリ名>]$ rails db:create RAILS_ENV=production
Created database '<データベース名>'
[ec2-user@<自身のElasticIP> <リポジトリ名>]$ rails db:migrate RAILS_ENV=production

# Railsの起動
[ec2-user@<自身のElasticIP> ~]$ cd /var/www/[リポジトリ]
[ec2-user@<自身のElasticIP> <リポジトリ名>]$ bundle exec unicorn_rails -c config/unicorn.rb -E production -D
```

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

##### アセットファイルをコンパイルしましょう
```
[ec2-user@<自身のEalsiticIP> <リポジトリ名>]$ rails assets:precompile RAILS_ENV=production
```
ここまで終えたら再度Railsを起動させたいのですが、すでにサーバーは立ち上がっています。

#### Railsを再起動
まず、「Unicornのプロセス」を確認します。ターミナルからプロセスを確認するには「psコマンド」を利用します。

##### psコマンド
「psコマンド」とは、現在動いているプロセスを確認するためのコマンドです。それでは「psコマンド」を実行し、Unicornのプロセスを確認しましょう。

```
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn
# ここで表示される最初の数字がプロセスのIDになります。
```

##### プロセスid
プロセスidは、プロセスを識別するための一意の数字です。PIDがあることで、あるプログラムから別のプロセスを指定して操作したり、プロセスからプログラムを停止したりできます。

##### killコマンド
killコマンドは、現在動いているプロセスを停止させるためのコマンドです。

```
[ec2-user@<自身のElasticIP> <リポジトリ名>]$ kill <確認したunicorn rails masterのプロセスid>

# 終了できているか確認
[ec2-user@<自身のElasticIP> <リポジトリ名>]$ ps aux | grep unicorn
```
最後に、Railsを再起動するコマンドを実行しましょう。
##### RAILS_SERVE_STATIC_FILES=1
「RAILS_SERVE_STATIC_FILES=1」は、Railsがコンパイルされたアセットを見つけられるように指定する役割があります。

```
[ec2-user@<ElasticIP> <リポジトリ名>]$ RAILS_SERVE_STATIC_FILES=1 unicorn_rails -c config/unicorn.rb -E production -D
# ブラウザで http://＜Elastic IP＞:3000/ にアクセスして、サイトが正常に表示されているか確認してみましょう。
```
以上がRailsを使用した手動デプロイの方法になります！参考までにどうぞ！