EC2上でRailsを起動


目的

本番環境でRailsを起動すること

EC2上でRailsを起動するための設定

ここまでEC2インスタンス内にRubyなどのツールをインストールし、アプリケーションを配置するための環境を整えました。
次は、いよいよ開発したアプリケーションを全世界に公開(デプロイ)します。

EC2のサーバーに開発中のアプリケーションのコードをクローンする準備をする

アプリケーションのコードをGitHubからEC2サーバへクローンします。デプロイできるIPアドレスを持ったEC2サーバー上でアプリケーションを動かすためです。
現状、EC2サーバにアプリケーションのコードをクローンしようとしても「permission denied」とエラーが出てしまいます。
これは、GitHubから見てこのEC2インスタンスが何者かわからないためです。
EC2インスタンスからGitHubにアクセスするためには、作成したEC2インスタンスのssh公開鍵をGitHubに登録する必要があります。
ssh鍵をGitHubに登録すると、GitHubはそれを認証に利用し、コードのクローンを許可してくれるようになります。

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

以下のコマンド入力して、EC2サーバのssh鍵ペアを作成しましょう

途中で「passphrase」など3段階ほど入力を求められることがありますが、すべて何も入力せずにEnterキーを押して進んでください。

[ec2-user@ip-172-31-23-189 ~]$ 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コマンド」を実行することで、そのファイルの具体的な内容をターミナル上で確認できます。
catコマンドで、公開鍵が含まれているファイルid_rsa.pubの中身をターミナル上に表示します。

[ec2-user@ip-172-31-23-189 ~]$ cat ~/.ssh/id_rsa.pub

そして、以下のように表示される公開鍵の情報をすべて(「ssh-rsa」から「末尾の文字」まで)コピーします。

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLwt......
# 表示された内容すべてをコピー

次に、コピーした公開鍵をGitHubに登録します。
まず、以下のリンクにアクセスしてください。
https://github.com/settings/keys
画面遷移後、右上にある「New SSH key」をクリックしましょう。
次の画面では、公開鍵のタイトルを設定し、コピーした公開鍵を貼り付けましょう。入力ができたら、「Add SSH key」をクリックして公開鍵を保存します。

GitHubに鍵を登録できたら、ssh接続できるか以下のコマンドで確認してみましょう。

[ec2-user@ip-172-31-23-189 ~]$ ssh -T [email protected]
Hi <Githubユーザー名>! You've successfully authenticated, but GitHub does not provide shell access.

途中でこのまま続けるかどうか、「Yes/No」または「y/n」などの選択肢で聞かれることがあります。その場合は「Yes」または「y」などの「許容」を意味する入力をし、Enterキーを押下して進んでください。
「Permission denied (publickey).」と表示された場合は、ssh鍵の設定が間違っているので、再度作業を確認しましょう。

アプリケーションサーバーの設定

「アプリケーションサーバー」とは、ブラウザからの「リクエスト」を受け付けRailsアプリケーションを実際に動作させるソフトウェアのことです。
ローカル環境でRuby on Railsのアプリケーションの動作を確認する際、以下の手順を踏むと思います。
① ターミナルで「rails sコマンド」を打つ
② ブラウザで「localhost:3000」にアクセスする
①をせずに②を行なっても、アプリケーションの動作は確認できません。
この①の操作はまさに「アプリケーションサーバーの起動」を行なっています。
rails sコマンドを打つと「puma」と呼ばれるアプリケーションサーバーが起動しています。
また、localhost:3000とは「自身のPCを指すドメイン」のことです。
アプリケーションサーバーが動いていれば、ブラウザからのリクエストを受け付けてRailsアプリケーションが動作します。
全世界に公開するEC2サーバー上でもアプリケーションサーバを動かす必要があります。
そのために必要なツールが「Unicorn」と呼ばれるものです。

Unicorn

「Unicorn」とは、全世界に公開されるサーバ上で良く利用されるアプリケーションサーバーです。rails sコマンドの代わりに「unicorn_railsコマンド」で起動することができます。
EC2サーバにssh接続しUnicornを起動することで全世界からアクセスできるようにします。
ここで、Unicornを理解するために必要な概念である「プロセス」についても押さえておきましょう。

プロセス

「プロセス」とは、PC上で動くすべてのプログラムの実行時の単位です。ここで言うプログラムとは、ブラウザや音楽再生ソフト、ExcelといったGUIや、Rubyなどのスクリプト言語の実行などが含まれます。
プログラムが動いている数だけ、プロセスが存在しています。たとえばテキストエディタを起動する時、テキストエディタ用のプロセスが生み出されます。
Unicornなどのアプリケーションサーバを起動するとアプリケーションサーバのプロセスが生まれます。アプリケーションサーバのプロセスがあれば、リクエストを受け付けブラウザにレスポンスを返すことができます。

Unicornをインストール

ここからは、実際にUnicornを使えるさまざまな設定をします。

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

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

編集したら「bundle install」
次に「config/unicorn.rb」を作成し、内容を以下のように編集して保存しましょう

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の数を決定します。

ブラウザなどからリクエストが来ると、UnicornのworkerがRailsアプリケーションを動かします。Railsは、リクエストの内容とルーティングを照らし合わせ最終的に適切なビュー(HTML)もしくはJSONをレスポンスします。レスポンスを受け取ったUnicornは、それをブラウザに返します。一連の動きはおよそ0.1 ~ 0.5秒程度で行われます。常にそれ以上のスピードでリクエストが頻発するようなアプリケーションだと、1つのworkerだけでは処理が追いつかず、レスポンスまで長い時間がかかってしまったり最悪サーバがストップしてしまいます。そんな時、worker_processesの数を 2,3,4と増やすことでアプリケーションからのレスポンスを早くできます
①worker_processes |リクエストを受け付けレスポンスを生成するworker(ワーカー)の数を決めます。
②working_directory |UnicornがRailsのコードを動かす際、ルーティングなど実際に参照するファイルを探すディレクトリを指定します。
③pid |Unicornは、起動する際にプロセスidが書かれたファイルを生成します。その場所を指定します。
④listen| どのポート番号のリクエストを受け付けることにするかを決定します。今回は、3000番ポートを指定しています。

GitHubnにpushしリモートリポジトリに反映ができたら、ここまでのローカルの全内容をEC2に反映します。

EC2にローカルの全内容を反映しましょう

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

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

次に、GitHubから「リポジトリURL」を取得し、クローンします。
デプロイするアプリケーションのGitHubを開きましょう。緑色で「Code」と表示されているボタンをクリックして、URLをコピーします。

URLがコピーできたら、コードをクローンします。

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

本番環境での設定

現状動かしているEC2のインスタンスではコンピューターの能力が足りず、Gemのインストール時などにエラーが発生する可能性があります。具体的には、コンピューターの処理能力に関係するメモリというものが足りません。これは、無料で動かせるインスタンスの限界であるため仕方ありません。
そこで、今後の設定を行う前に「Swapファイル」というメモリを増強する処理を行います。

Swap(スワップ)ファイル

「Swapファイル」とは、メモリの容量を一時的に増やすために準備されるファイルのことです。コンピューターが処理を行う際、メモリと呼ばれる場所に処理内容が一時的に記録されます。メモリは容量が決まっており、容量を超えてしまうとエラーで処理が止まってしまいます。

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

まずは、EC2にssh接続をしてホームディレクトリに移動します。

# ホームディレクトリに移動
[ec2-user@ip-172-31-25-189 ~]$ cd

次に以下のコマンドを打ち込みます。


[ec2-user@ip-172-31-25-189 ~]$ 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-172-31-25-189 ~]$ sudo chmod 600 /swapfile1
[ec2-user@ip-172-31-25-189 ~]$ sudo mkswap /swapfile1

# 以下のように表示されれば成功
スワップ空間バージョン1を設定します、サイズ = 524284 KiB
ラベルはありません, UUID=74a961ba-7a33-4c18-b1cd-9779bcda8ab1
[ec2-user@ip-172-31-25-189 ~]$ sudo swapon /swapfile1
[ec2-user@ip-172-31-25-189 ~]$ sudo sh -c 'echo "/swapfile1  none        swap    sw              0   0" >> /etc/fstab'

これで、Swapファイルの領域を確保することができました。

EC2内でgemをインストールする

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

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

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

次に、本番環境で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-172-31-23-189 <リポジトリ名>]$ gem install bundler -v 2.1.4

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

環境変数を設定

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

それでは、secret_key_baseを環境変数に設定しましょう。

[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ rake secret
69619d9a75b78f2e1c87ec5e07541b42f23efeb6a54e97da3723de06fe74af29d5718adff77d2b04b2805d3a1e143fa61baacfbf4ca2c6fcc608cff8d5a28e8d

次に、EC2内に環境変数を設定しましょう。

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

[ec2-user@ip-172-31-23-189 ~]$ sudo vim /etc/environment

「i」と打ち込んで入力モードに切り替えます。下記の記述を打ち込みます。

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

# 「AWSに画像をアップロードする」でダウンロードしたCSVファイルを参考に値を入力
AWS_ACCESS_KEY_ID='ここにCSVファイルのAccess key IDの値をコピー'
AWS_SECRET_ACCESS_KEY='ここにCSVファイルのSecret access keyの値をコピー'

入力を終えたら「escキー」→「:wq」の順で実行し、保存しましょう。

設定した環境変数を反映させるために、一度本番環境をログアウトします。

[ec2-user@ip-172-31-23-189 ~]$ exit
logout
Connection to 52.xx.xx.xx closed.

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

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

接続し直したら、「envコマンド」と「grepコマンド」を組み合わせて、さきほど設定した環境変数が適用されているか確認します。
「envコマンド」とは、設定されている環境変数を表示するためのコマンドです。envは「environment(環境)」の略称です。このコマンドで全環境変数を表示できます。
「grepコマンド」は、環境変数などを検索するときに使います。使い方は「grep (検索対象)」となります。
それでは上記のコマンドを使って確認します。

[ec2-user@ip-172-31-23-189 ~]$ env | grep SECRET_KEY_BASE
SECRET_KEY_BASE='secret_key_base'
![スクリーンショット 2021-01-05 12.37.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/918688/690162cc-6a61-498b-2f9e-a35856237883.png)

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

[ec2-user@ip-172-31-23-189 ~]$ env | grep AWS_SECRET_ACCESS_KEY
AWS_SECRET_ACCESS_KEY='Secret access key'

[ec2-user@ip-172-31-23-189 ~]$ env | grep AWS_ACCESS_KEY_ID
AWS_ACCESS_KEY_ID='Access key ID'

次回はポートの開放を投稿します