AWS Elastic BeanstalkでRails5アプリをデプロイする際の注意点(前編)

# この記事

Railsで作ったアプリをBeanstalkで公開する手順を後で見返せるようにメモ。

# 環境(RubyとBundlerは執筆時のBeanstalkが対応している最新版)

- Rails5
- Ruby 2.4.2
- Bundler 1.15.0
- webpaker 3.0.2

# 事前準備

IAMの設定やAWS CLIの設定とElastic Beanstalk用のCLIのダウンロードなどは終わっていることとします。
下記の記事が設定周りまでわかりやすかったです。
[Ruby on Railsの環境構築をElastic Beanstalkで行う](https://qiita.com/yuyasat/items/4d93b4ad4f86a6e13d50)

# 手順

### 初期化

`eb.init`コマンドで初期化すると下記の項目を聞かれるので適宜設定。

- default regionの選択
- アクセスキーとシークレットキーを登録
- アプリケーション名の登録(AWSコンソール画面に表示されるもの)
- 環境の選択（ruby2.4(Puma)を選択しました）
- CodeCommitを利用するか(最初はnoの方がやりやすいかと)
- 立ち上げるEC2にssh接続するか(yesにするとkey pair nameとかパスを聞いてくれて自動で公開鍵のアップロードまでしてくれるので楽)

### 環境の作成

`eb create`で環境の作成が可能。

- 環境名。デフォルトは`アプリケーション名-dev`となる。
- DNS CNAME prefix(デフォルトは環境名と一緒)
- ロードバランサーのタイプ(クラシック/アプリケーション/ネットワークを選べる)

### デプロイ

`eb deploy`でデプロイ可能。

→ただし、このままではDBも設定していないので動きません。

[Ruby on Railsの環境構築をElastic Beanstalkで行う](https://qiita.com/yuyasat/items/4d93b4ad4f86a6e13d50)

こちらの記事を参考にRDSの作成をやりましょう。

エラーログなどを見たい場合は`eb logs`で見れます。
AWSのコンソール画面からも見れます。

# 注意点やハマったポイント

### ebとgitの関係性

`git commit`していないとデプロイには反映されないです。
ebのymlの設定で`sc: git`となっているため、変更の管理がgit配下と同じ扱いなんですね。

→`git add .` していれば `--staged`　オプションをつけることでデプロイ可能です。

### commandsの設定

自分で `.ebextensions`フォルダを作成して、`hogehoge.config`のようなファイル名で保存し、そこの中にyamlで記述する必要があります。
option関連は、`.elasticbeanstalk/config.yml`に追記しても実行されないです。
自分がうまくいった環境はこちらのような内容です。
[Deploy on AWS Beanstalk](https://github.com/rails/webpacker/issues/118)
ここの情報のままでうまくyarnがinstallされました。

``` yarn.config
files:
  # If this file is edited, it must be removed from EC2 instance prior to deploy.
  "/opt/elasticbeanstalk/hooks/appdeploy/pre/09_yarn_install.sh" :
    mode: "000775"
    owner: root
    group: users
    content: |
      #!/usr/bin/env bash

      set -xe

      EB_APP_STAGING_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_staging_dir)
      EB_APP_USER=$(/opt/elasticbeanstalk/bin/get-config container -k app_user)

      echo "I am: `whoami`"
      echo "App user is $EB_APP_USER"

      # If yarn is not detected, install it.
      if which yarn; then
        echo "Skipping installation of yarn -- yarn already installed."
        echo "yarn --version: `yarn --version`"
      else
        echo "which yarn: `which yarn`"
        echo "Yarn is not installed and accessible."
        echo "Installing yarn..."
        # Consider that the EC2 instance is managed by AWS Elastic Beanstalk.
        # Changes made via SSH WILL BE LOST if the instance is replaced by auto-scaling.
        # QUESTION: Will this script be run on new instances that are created by auto-scaling?
        # QUESTION: Should installation be moved to a rake task?

        # Download the yarn repo
        sudo wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo
        # Confirm that it downloaded
        file /etc/yum.repos.d/yarn.repo

        # If node is not detected, install it.
        if [ `node --version` == 'v6.10.0' ]; then
          echo "Skipping installation of node -- node already installed."
          echo "node --version: `node --version`"
        else
          echo "Installing Node v6.10.0 ..."
          # Download the Node v6 setup script
          curl --location https://rpm.nodesource.com/setup_6.x > /home/ec2-user/node_install.sh
          # Confirm that it downloaded
          file /home/ec2-user/node_install.sh
          # Run the Node v6 setup script
          sudo bash /home/ec2-user/node_install.sh
          # Install nodejs
          sudo yum install -y nodejs
          node --version
          echo "... and finished installing Node v6.10.0"
        fi

        # install yarn
        sudo yum install -y yarn
        yarn --version

        echo "... and finished installing yarn."
      fi

      echo "Change directory to $EB_APP_STAGING_DIR"
      cd $EB_APP_STAGING_DIR

      # yarn install
      echo "Running yarn install."
      ./bin/yarn install
```

### database名

上記で紹介した記事のように、ElasticBeanstalkのコンソール上からRDSを作成するとDB名は勝手に`ebdb`になってしまいます。
変える方法はめんどくさそうなので試してません。（もしかするとできないかもしれないです。）

### DBの文字コード

上記方法で作るとDBの文字コードが下記のようになってしまいます。

```
'character_set_client', 'utf8'
'character_set_connection', 'utf8'
'character_set_database', 'latin1'
'character_set_filesystem', 'binary'
'character_set_results', 'utf8'
'character_set_server', 'latin1'
'character_set_system', 'utf8'
'character_sets_dir', '/rdsdbbin/mysql-5.6.37.R1/share/charsets/'
```

日本語とかを入れようとするとエラーになってしまうので、手動でUTF-8に変更しました。

```
ALTER DATABASE ebdb default character set utf8;
ALTER TABLE テーブル名 CONVERT TO CHARACTER SET utf8;
```

### dbのマイグレーションなど

bundleのinstallやdbのマイグレーションはcontainer_commandsというセクションで行います。
結果、configファイルは下記のような感じに落ち着きました。

``` container_commands.config
container_commands:
  01-bundle_install:
    command: bundle install --path vendor/bundle
  02-db_migrate:
    command: bundle exec rake db:migrate
  03-db_seed:
    command: bundle exec rake db:seed
  04-assets_precompile:
    command: bundle exec rake assets:precompile
  05-chown:
    command: chown -R webapp:webapp ./
```

### 画像のファイルパス

assets/imagesに入れている画像の参照パスはproduction環境とローカル環境で変わってしまいます。
nginxの設定にもよりますが、自分の環境では下記のようなwebpackerの設定でうまくいきました。

``` webpacker.yml
default: &default
  source_path: app/javascript
  source_entry_path: packs
  public_output_path: packs

production:
  <<: *default

  public_output_path: assets
```

# 最後に

AWS Elastic BeanstalkでRailsアプリをデプロイする際の参考になれば幸いです。
Railsはまだ初心者のため、色々ご指摘ありましたら優しく教えてください。

# 追記

上記設定では再デプロイ時にエラーが出ていたので、[後編](https://qiita.com/takahiro096041/items/ddf1a73e755b6e7a1b7f)を書きました。


# 参考

- [Ruby on Railsの環境構築をElastic Beanstalkで行う](https://qiita.com/yuyasat/items/4d93b4ad4f86a6e13d50)
- [rails 5.1.1 をvueとreactをインストールしてAWS Elastic Beanstalkで表示するまで](https://qiita.com/junara/items/ae09c94da5223c9c3aff)
- [Deploy on AWS Beanstalk](https://github.com/rails/webpacker/issues/118)
- [RDS付きのBeanstalkを使う際の注意点](http://blog.serverworks.co.jp/tech/2013/03/12/rds_on_beanstalk/)
- [RDSに作成したMySqlのDatabaseに日本語が登録出来ない問題](https://qiita.com/kijitora-neko/items/aab58b4c1f684353e075)