rails 5.1.1 をvueとreactをインストールしてAWS Elastic Beanstalkで表示するまで


# 概要
rails5.1.1をvueとreact readyのアプリをインストールし、ローカルとAWS Elasticbeanstalkで表示するまでの手順を示す。
~~ただしElastic Beanstalkは、nginxの調査が足りないため暫定的な方法を記した。~~ webpackerの設定をすることで出来るようになりました。


# 環境
## ローカル
* rbenv 2.3.1
* macOS Sierra
* yarnインストール済
* npmインストール済
* gitインストール済（SourceTreeでも可）

## 本番（AWS Elastic Beanstalk）
* AWSアカウント持ってる
* ebとawsのCLIがローカルにインストールされている。

# ローカル環境で動かすまで
## yarnを最新バージョンにする

```console
brew upgrade yarn
```

## railsインストール

* bundle初期化

rbenvでlocalのバージョンを2.3.1にセット（バージョンはなんでもいいです。）

```console
rbenv local 2.3.1
```

```console
rbenv exec bundle init
```

* rails インストール準備

```Gemfile
gem 'rails'
```

* rails インストール

bundleのインストール先として、 __vendor/bundler__ を指定しました。

```console
rbenv exec bundle install --path vendor/bundler
rbenv exec bundle exec rails new . --webpack
（途中Gemfileの上書きして良いか聞かれるのでYを選択。）
rbenv exec bundle exec rails webpacker:install:vue
rbenv exec bundle exec rails webpacker:install:react

```

## vueとreact動作確認用の設定

```app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
  def home
  end
end
```

```config/routes.rb
Rails.application.routes.draw do
  root to: 'static_pages#home'
end
```

```app/views/static_pages/home.html.erb
<%= javascript_pack_tag 'hello_vue' %>
<%= javascript_pack_tag 'hello_react' %>
```

## サーバー起動
__rails server__ と __webpack-dev-server__ を両方起動する

```console
rbenv exec bundle exec rails s
bin/webpack-dev-server 
```

## アクセスしてみる
* [http://localhost:3000](http://localhost:3000)

[![https://gyazo.com/0b036f1b28c893fa4c73aacdf11a751f](https://i.gyazo.com/0b036f1b28c893fa4c73aacdf11a751f.png)](https://gyazo.com/0b036f1b28c893fa4c73aacdf11a751f)

# 本番環境（AWS ElasticBeanstalk）で動かすための追加設定

このまま、デプロイしても失敗する。

失敗する原因は以下の3つ。

1. webpackerが使うyarnがEBSにインストールされていない
2. yarnをインストールする前に、rake assets:precompile が行われてしまう
3. publick/pack配下のwebpack が変換したjavascriptをnginxがアセットとして認識してくれない
	* http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/create_deploy_Ruby_rails.html
	* https://teratail.com/questions/70641

~~1と2は解決法を、3については暫定的な対応策を示す。~~


## その前にEBSにデプロイするための一般的な設定

こちらの[Ruby on Railsの環境構築をElastic Beanstalkで行う](http://qiita.com/yuyasat/items/4d93b4ad4f86a6e13d50)の通りすすめればOK。（かなり丁寧に説明されています。）

上記と重複しますが、もし、上記でうまく行かなかったら参考になるかもしれませんので、自分の作業手順を記します。

### postgresql用のgemインストール
* elastic beanstalkでpostgresqlを使うようにrailsを修正

```Gemfile
###省略###
# postgreSQL
gem 'pg'

```

```console
rbenv exec bundle install
```

### データベースの設定をEBSの環境変数から読み込むように修正
```config/database.yml

###省略###

production:
  <<: *default
  adapter: postgresql
  database: <%= ENV["RDS_DB_NAME"] %>
  username: <%= ENV["RDS_USERNAME"] %>
  password: <%= ENV["RDS_PASSWORD"] %>
  host: <%= ENV["RDS_HOSTNAME"] %>
  port: <%= ENV["RDS_PORT"] %>
```

### IAM ユーザ作成

* awsでIAM でelastic beacnstalkに接続できる権限を有するユーザを作成し、 __アクセスキーID__ と __シークレットアクセスキー__ を取得

### awsの接続設定
* awsコマンドラインツールとebコマンドラインを事前にインストールしておいて、以下を実行

```
> aws configure
AWS Access Key ID [****************LSGQ]: アクセスキーID
AWS Secret Access Key [****************FmS9]: シークレットアクセスキー
Default region name [ap-northeast-1]: 
Default output format [json]: 
```

### elastic beanstalkの設定フォルダ（ __.elasticbeanstalk__  ）をコマンドラインで作成
* 事前準備：AWSのキー（今回はaws-eb2をつくっておきました）
* アプリ直下のフォルダで操作ターミナル操作してください。


```
> eb init
Select a default region
1) us-east-1 : US East (N. Virginia)
2) us-west-1 : US West (N. California)
3) us-west-2 : US West (Oregon)
4) eu-west-1 : EU (Ireland)
5) eu-central-1 : EU (Frankfurt)
6) ap-south-1 : Asia Pacific (Mumbai)
7) ap-southeast-1 : Asia Pacific (Singapore)
8) ap-southeast-2 : Asia Pacific (Sydney)
9) ap-northeast-1 : Asia Pacific (Tokyo)
10) ap-northeast-2 : Asia Pacific (Seoul)
11) sa-east-1 : South America (Sao Paulo)
12) cn-north-1 : China (Beijing)
13) us-east-2 : US East (Ohio)
14) ca-central-1 : Canada (Central)
15) eu-west-2 : EU (London)
(default is 3): 9

Select an application to use
1) rails-base
2) [ Create new Application ]
(default is 1): 

It appears you are using Ruby. Is this correct?
(Y/n): 

Select a platform version.
1) Ruby 2.3 (Puma)
2) Ruby 2.2 (Puma)
3) Ruby 2.1 (Puma)
4) Ruby 2.0 (Puma)
5) Ruby 2.3 (Passenger Standalone)
6) Ruby 2.2 (Passenger Standalone)
7) Ruby 2.1 (Passenger Standalone)
8) Ruby 2.0 (Passenger Standalone)
9) Ruby 1.9.3
(default is 1): 
Do you want to set up SSH for your instances?
(Y/n): 

Select a keypair.
1) aws-eb
2) aws-eb2 
3) [ Create new KeyPair ]
(default is 2): 

```

上記を実行すると以下のファイルが作成されます。
（rails-baseというのは、アプリ名です。それぞれのアプリで異なります。）

```.elasticbeanstalk/config.yml
branch-defaults:
  elasticbeanstalk:
    environment: null
global:
  application_name: rails-base
  branch: null
  default_ec2_keyname: aws-eb2
  default_platform: Ruby 2.3 (Puma)
  default_region: ap-northeast-1
  instance_profile: null
  platform_name: null
  platform_version: null
  profile: eb-cli
  repository: null
  sc: git
  workspace_type: Application

```

### 変更した内容をgitにコミットする

elasticbeanstalkにアップロードするファイルはgitでcommitされたファイル。

よってこれまでの変更をcommitする。

リポジトリを作成

```
git init
```

これまでの変更をgitのステージにあげる

```
git add .
```

gitにコミットする

```
git commit -m 'first commit desu'
```


### elastic beastalkの新しいアプリケーションを作成

以下を実行する。
ただし、データベースの設定をしていないので失敗します。でも気にしない。


```
 eb create
Enter Environment Name
(default is rails-base-dev): 
Enter DNS CNAME prefix
(default is rails-base-dev): 
Select a load balancer type
1) classic
2) application
(default is 1): 

```

以下のようなエラーメッセージで終了するはず。

```
INFO: Command execution completed on all instances. Summary: [Successful: 0, Failed: 1].
WARN: Environment health has transitioned from Pending to Degraded. Command failed on all instances. Initialization completed 24 seconds ago and took 4 minutes.
ERROR: Create environment operation is complete, but with errors. For more information, see troubleshooting documentation.

```

### データベースの追加

[RDSの作成](http://qiita.com/yuyasat/items/4d93b4ad4f86a6e13d50#rds%E3%81%AE%E4%BD%9C%E6%88%90)を参照してデータベースを追加する。

### railsサーバー用のシークレットキーの生成

下記でシークレットキーを作成する。

```
rbenv exec bundle exec rake secret
```

### elasticbeanstalkの環境変数の設定
下記のコマンドを実行して、環境変数を設定します。
わかりやすさを重視して、環境変数を1個ずつ設定するようにしました。
しかし、設定毎に、デプロイが行われ（かつ失敗する！）のでうざいかも。

```
eb setenv RDS_DB_NAME=ebdb
eb setenv RDS_USERNAME=データベースのユーザ名
eb setenv RDS_HOSTNAME=データベースの接続アドレス
eb setenv RDS_PASSWORD=データベースの接続パスワード
eb setenv RDS_PORT=5432
eb setenv SECRET_KEY_BASE=railsサーバー用のシークレットキー

```

その場合は、上記のリンク先を参照して、下記の様に1行にして実行してください。うざい回数が減ります。


```
eb setenv RDS_DB_NAME=ebdb RDS_USERNAME=データベースのユーザ名 RDS_HOSTNAME=データベースの接続アドレス RDS_PASSWORD=データベースの接続パスワード RDS_PORT=5432 SECRET_KEY_BASE=railsサーバー用のシークレットキー
```


一般的なEBSの設定はここまで。

でも前述の通り、これだけではデプロイに失敗するので、追加の設定をします。

## 追加の設定
### webpackerが使うyarnがEBSにインストールされていないへの対処

yarnをインストールするための設定を __.ebextensions__ に書き込みます。

コードは以下のリンク先のままです。内容は、yarn公式のインストールコマンドを並べただけです。

[Customize AWS ElasticBeanstalk NodeJS Install (use yarn)](https://stackoverflow.com/questions/41657226/customize-aws-elasticbeanstalk-nodejs-install-use-yarn)

```.ebextensions/02_yarn.config
commands:
  02_install_yarn:
    command: "sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo && curl --silent --location https://rpm.nodesource.com/setup_6.x | sudo bash - && sudo yum install yarn -y"
```

### yarnをインストールする前に、rake assets:precompile が行われてしまうへの対処
EBSの環境変数 __RAILS_SKIP_ASSET_COMPILATION__ を __true__ にすると __rake assets:precompile__ を抑制できます。
下記のコマンドで環境変数を追加します。

```
eb setenv RAILS_SKIP_ASSET_COMPILATION=true

```

ただし、このままだとprecompileされません。前述のyarnのインストールの後に実行されるように  __.ebextensions__ に __bundle exec rake assets:precompile__ を実行する命令を追加します。


```.ebextensions/02_yarn.config
commands:
  02_install_yarn:
    command: "sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo && curl --silent --location https://rpm.nodesource.com/setup_6.x | sudo bash - && sudo yum install yarn -y"
container_commands:
  03_compile-assets:
    command: bundle exec rake assets:precompile

```

### publick/pack配下のwebpack が変換したjavascriptをnginxがアセットとして認識してくれないへの対処

（以前の文書（webpacker 1.2の場合）は文末に移動しました。）

webpackerが2.0であることを確認してください（Gemfile.lockを見るとよいです）。もし、webpackerが1.2以下ならば、[wepacker git page](https://github.com/rails/webpacker/blob/master/CHANGELOG.md)を参照して、アップデートしてください。ただし、下記の手順は新規インストールを前提にしています。また、 __アップデートに伴う既存のwebpackerの設定ヘの影響は検証していません。__ 

EBSのnginxがアセットとして認識するのはpublic直下とpublic/assets。
一方、webpackerがデフォルトでアセットを作成するのはpublic/packs。
この差異を解決するため、webpacker.ymlを編集します。


```config/webpacker.yml
default: &default
  source_path: app/javascript
  source_entry_path: packs
  public_output_path: assets # ここをpacksからassetsに変更した
省略
```


## デプロイする

前述の結果をgitにコミットします。

下記のコマンドでデプロイする。

```console
eb deploy
```


ルートパスにアクセスするとローカル環境と同じhello vue!やhello react!などの文字が表示されることを確認してください。

表示されていれば、本番環境へのデプロイが無事されています。

# 付録1：独自ドメイン取得と登録
[過去記事 AWS Route 53でElastic Beanstalkのアプリをドメイン登録](http://qiita.com/junara/items/62b0e11f71111ef8e4ce)

# 付録2：HTTPS対応
* 下記でかなり丁寧に説明されています。
    * 
[Elastic BeanstalkでAWS上にHTTPS対応のRailsアプリケーションを構築する](http://blog.wackwack.net/entry/2017/02/07/223956)

# 備考
~~nginxの箇所は理解できたら追記します。~~ ~~とりあえず使えるようになったので別の機会に勉強します。~~ @kansiho さんコメントありがとうございます。

`.ebextensions/`にhttps://gist.github.com/ankitsinghaniyaz/48b3276d344668dff82a2b1cc3a8d455 のファイルを追加すればよいと思います。

下記の箇所の記述により、`assets`と`packs`どちらでアクセスしてもキチンと`public`配下を検索してくれるみたいです。


```nginx_proxy.config
省略
          location ^~ /assets/ {
            root /var/app/current/public;
          }

          # commented out for now in favor of rails serving the files
          location ^~ /packs/ {
            root /var/app/current/public;
          }
省略
```

# 古い文書（webpacker 1.2以前の場合）
## publick/pack配下のwebpack が変換したjavascriptをnginxがアセットとして認識してくれないへの対処

先に断っておくと、 __nginxに public/pack配下をアセットとして認識させる方法__ はわかりませんでした。
よって、今回は __nginxのアセットを使わないとする__ ことで __暫定的にEBSで起動させる__ 方法をとりました。

```config/environments/production.rb
  # Disable serving static files from the `/public` folder by default since
  # Apache or NGINX already handles this.
  # config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? #これをコメントアウト
  config.public_file_server.enabled = true # これを追加
```