Ruby on Railsの環境構築をElastic Beanstalkで行う

# この記事について
- 最近は、主にTipsのところを更新しており、Elastic Beanstalkに関する私的メモのような感じになっております。
- 2019-04-03 assets:precompileについて を追加
- 2021-01-21 PlantoformにAmazonLinux2をを利用する場合、eb-activitiy.logがeb-engine.logになる旨を追記
- 2021-03-23 PlantoformにAmazonLinux2をを利用する場合の環境変数読み込みについて追記

# Elastic Beanstalkとは
- アプリケーションのインフラ周りをよしなにやってくれるAWSが提供するPaaS
- もう少し説明すると、Webアプリを公開する場合、Webサーバ、アプリケーションサーバ、DBサーバを立てて、それぞれを連携させる必要があります。場合によってはロードバランサ(ELB)でリクエストを分散させる仕組みを構築したり、サーバーを監視(CloudWatch)したりするインフラを整備する必要があります。Auto Scalingも考えなければいけません。Elastic Beanstalkは、そうしたインフラ周りの構築をよしなにやってくれます。詳しくは[AWS Elastic Beanstalk とは?](http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/Welcome.html)をご覧ください。
- Ruby on Railsだと、たとえばWebサーバにnginx、アプリケーションサーバにunicorn、データベースサーバにはAWSのRDSを使うといったことが多いかと思いますが、Elastic Beanstalkでは、Webサーバーにnginx、アプリケーションサーバーにはPumaまたはPassengerが用意されています。データベースサーバは現状ではRDSは手で作ってあげる必要がある模様です。詳しくは[サポートされているプラットフォーム Ruby](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/platforms/platforms-supported.html#platforms-supported.ruby)をご覧ください。
- Elastic Benastalkにはcliツールが用意されており、`eb`コマンドを使用することで、簡単に初期設定やdeployなどを行うことができます。
- Elastic Beanstalkを使うための料金は基本的に無料です。ただし、構築されたEC2インスタンスやRDS等には(無料枠外であれば)課金されます。
- (余談)Elasticとは「柔軟な」、Beanstalkとは「豆の木」という意味です。そう「ジャックと豆の木」の「豆の木」です。([詳細](http://www.atmarkit.co.jp/ait/articles/1106/15/news128.html))

# 今回作成する構成
- Webサーバにnginx、アプリケーションサーバにPuma、RDSはPostgresql 9.5で構成しようと思います。
- この記事は、Elastic Beanstalkで環境構築した際につまづいたことなどを逐次追記しています。
- ELB（Elastic Load Balancing）に関しては、1回目に構築した時は、Classic Load Balancerを用いています。2回目に構築した時はApplication Load Balancerを用いており、記述が併記されている箇所があります。

# 手順
- GUIでも出来るかと思いますが、`eb`コマンドを使ってcliで行います。
- 作業しているマシンはmacOS Sierraです。

### IAMユーザーの作成
- AWSのアカウントは作っているという前提で進めます。Elastic Beanstalkを使うには、IAMユーザーを作成する必要があります。
- AWSマネジメントコンソールから、IAMをクリックし、ユーザーを追加から追加してください。
- アクセスの種類は、今回はcliで作業するので、`プログラムによるアクセス`にチェック。マネジメントコンソールからも作業したくなるでしょうから`AWS マネジメントコンソールへのアクセス`にもチェックしておけば良いかと思います。お好みで。
- アクセス権限は`既存のポリシーを直接アタッチ`でも良いですし、今後Elastic Beanstalkでデプロイするユーザーが増えることを想定するのであれば、グループを作成してそこにユーザーを追加する形でも良いかと思います。私はグループを作成しました。
    - グループ名は`eb-deploy`などわかりやすい名前をつけます。お好みで。
    - ポリシーフィルターは`AWSElasticBeanstalkFullAccess`を入れておけば良いかと思います。
    ![group_plicies.png](https://qiita-image-store.s3.amazonaws.com/0/121304/c4904fca-3803-fb9f-b38d-de404344b1b6.png)


- `確認`、`ユーザーの作成`を行うとAccess Key IDやSecret Access Key、マネジメントコンソールにアクセス許可した場合はパスワードも表示されるかと思います。Access Key IDやSecret Access Keyはとても大事なので慎重に保管しておいてください。

### コマンドラインでAccess Key IDやSecret Access Keyの設定
- 作成したIAMユーザーで操作するためにAccess Key IDとSecret Access Keyの設定を行います。
- (注意) awscliをインストールしていない方はインストールしておいてください。（[詳細](http://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html)）
- `aws configure`と打つと、対話形式で聞いてくるのでIAMユーザー作成の際に表示されたAccess Key IDとSecret Access Keyを入力します。`Default region name`は`ap-northeast-1`、Default output formatは`json`あたりを指定しておけば良いかと思います。

```
$ aws configure
AWS Access Key ID [None]: *********
AWS Secret Access Key [None]: **********************
Default region name [None]: ap-northeast-1
Default output format [None]: json
```
- 設定した値は

```
$ cat ~/.aws/config
$ cat ~/.aws/credentials
````
で確認できます。
なお、profile名を指定したい場合は、`aws configure --profile your-profile-name`とします。

### Elastic Beanstalkのセットアップ
- まず、`eb`コマンドをインストールします。homebrewでインストールします。（[詳細](http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/eb-cli3-install-osx.html)）

```
$ brew install awsebcli
$ eb --version
EB CLI 3.9.0 (Python 2.7.1)
```
- `eb init`コマンドで初期化します。
    - 対象となるリポジトリで作業して下さい。
    - こちらも対話形式で聞いてきますので、以下に私の場合の例を載せます。`#`以下はコメントになります。

```
$ eb init
Select a default region
1) us-east-1 : US East (N. Virginia)
・・・(中略)
9) ap-northeast-1 : Asia Pacific (Tokyo)
・・・(中略)
15) eu-west-2 : EU (London)
(default is 3): 9

Enter Application Name
(default is "sample-app"): sample-app　# デフォルトはリポジトリ名になると思われる

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

Select a platform version.
1) Ruby 2.3 (Puma)
・・・(中略)
8) Ruby 2.0 (Passenger Standalone)
9) Ruby 1.9.3
(default is 1): 1 # バージョンは各アプリで違うと思うのでお好みで。
Do you want to set up SSH for your instances?
(y/n): y

Select a keypair.
1) sample-app
2) [ Create new KeyPair ]
(default is 2): 1 # すでにあるkeypairを使う場合はそれを選択。keypairがない場合や新たなkeypairを使用する場合は、[ Create new KeyPair ]の番号を選ぶ。
```
- 設定は`cat .elasticbeanstalk/config.yml`で確認できます。

```
$ cat .elasticbeanstalk/config.yml
```

- このあたりで、`.gitignore`にElastic Beanstalk用のファイルは無視する設定が追加されるかと思います。リポジトリの`.gitignore`で管理したい場合は、`commit`しておきましょう。

```
git add .gitignore
git commit -m "add elastic beanstalk files to .gitignore"
```

- これで初期化が終わりました。

### アプリケーションの環境の作成
- これまでの作業でマネジメントコンソールからElastic Benastalkの管理画面に行くと、以下のような形になっているかと思います。
    ![eb-init.png](https://qiita-image-store.s3.amazonaws.com/0/121304/c96ebded-7e82-969d-a90c-612715e33cb3.png)
    - `今すぐ作成しましょう。`と書いてあるので作成しましょう。
- `eb create`で作成します。こちらも対話形式で設定が可能です。
- まず触ってみるだけならば、defaultのままで大丈夫かと思います。タイプしなくてもEnterで可能です。

```
$ eb create
Enter Environment Name
(default is sample-app-dev): sample-app-dev
Enter DNS CNAME prefix
(default is sample-app): sample-app # eb openコマンドで見れるときのURL。http://sample-app.ap-northeast-1.elasticbeanstalk.com/などとなる。

Select a load balancer type
1) classic
2) application
(default is 1): 1
```
- しばらく時間がかかるので、みかんでも食べて(冬場の場合)しばしお待ちください。コマンドラインにあるように`(safe to Ctrl+C)`なので`Ctrl+C`しても大丈夫です。経過はマネジメントコンソールから確認できます。

### RDSの作成
- しばらく待っていると、おそらく失敗すると思います。こういう場合は基本中の基本、ログを見ます。  
    ![error.png](https://qiita-image-store.s3.amazonaws.com/0/121304/8bee4f53-b455-bd9c-9f37-286435fba00e.png)
- `eb logs`コマンドでログが見れます。`eb logs`コマンドを実行すると`/var/log/nginx/error.log`など、複数のログが表示されます。今回のログはElastic Beanstalkに関するログなので、`/var/log/eb-activity.log`のとこ
ろを見ます。（AmazonLinux2では、`/var/log/eb-engine.log`になります）

```
$ eb logs
# lessで表示される。
-------------------------------------
/var/log/eb-activity.log
-------------------------------------
  ++ /opt/elasticbeanstalk/bin/get-config container -k app_user
  + EB_APP_USER=webapp
  ・・・(中略)
  + su -s /bin/bash -c 'leader_only bundle exec rake db:migrate' webapp
  rake aborted!
  PG::ConnectionBad: could not connect to server: No such file or directory
        Is the server running locally and accepting
        connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
```
- db:migrateができないよと言っているわけです。この辺りは、Railsの`config/database.yml`にどのように書かれているかにもよるのですが、defaultで`localhost`が指定されていてそれをproductionにも`<<: *default`のまま指定してあったりすると当然Elastic Beanstalkで作成されたEC2上にはデータベースサーバはありませんので、接続できないというわけです。
- これまで見てきた方法では、環境変数に本番環境のデータベースの情報を入れておいて、`config/database.yml`で`host: <%= ENV['DB_HOSTNAME'] %>`のようにしてある形も多かったです。そのような場合ですでにデータベースが作成されている場合は、Elastic Benastalkで作成したEC2からそのデータベースサーバに接続できるようにセキュリティーグループを設定してあげる必要があります。
- 今回の場合は新たにRDSを作成し、そこに接続するようにします。
- Elastic BeanstalkではRDSは作成してくれませんので、自分で作成します。
- Elastic Beanstalkの該当のアプリケーションのダッシュボードへ行き、左側にある`設定`をクリック。下の方にある`データ層`というところから、`新しい RDS データベースを作成`します。
    ![data-layer.png](https://qiita-image-store.s3.amazonaws.com/0/121304/f21acf3f-6ad3-bc5d-2cca-299c1c142c7e.png)
    - （画像は一部省略してあります)
- 作成するDBはお好みでいいのですが、無料枠だけでおさめたい場合はインスタンスクラスは`db.t2.micro`にしておく必要があるのでご注意ください。
    ![create-db.png](https://qiita-image-store.s3.amazonaws.com/0/121304/fe77e0a1-3a46-9f2d-a0db-ed83793677aa.png)
    - (画像は私の場合)
- RDSを作成すると、`エンドポイント`などが表示されると思います。また、マネジメントコンソールの`RDS`からも作成されているのが確認できるかと思います。そこでも`エンドポイント`や`ポート`などを確認できるかと思います。
- RDSへの接続は、AWSのDocumentにもあるように、config/database.ymlに設定しておかなければいけません。

```
default: &default
  adapter: postgresql
  encoding: unicode
・・・(中略)
production:
  <<: *default
  database: <%= ENV['RDS_DB_NAME'] %>
  username: <%= ENV['RDS_USERNAME'] %>
  password: <%= ENV['RDS_PASSWORD'] %>
  host: <%= ENV['RDS_HOSTNAME'] %>
  port: <%= ENV['RDS_PORT'] %>
```
- そして環境変数は、`eb setenv`コマンドで行います。

```
eb setenv RDS_DB_NAME=ebdb RDS_USERNAME=*********** RDS_PASSWORD=*********** RDS_HOSTNAME=***********.rds.amazonaws.com RDS_PORT=****
```

- 設定されている環境変数は、`eb printenv`コマンドで確認できます。

```
$ eb printenv
 Environment Variables:
     RDS_PORT = ****
     SECRET_KEY_BASE = ***************
     RAILS_SKIP_ASSET_COMPILATION = false
     RDS_DB_NAME = ebdb
     RACK_ENV = production
     RDS_PASSWD = *************
     RDS_USERNAME = *******
     BUNDLE_WITHOUT = test:development
     RAILS_SKIP_MIGRATIONS = false
     RDS_HOSTNAME = ************rds.amazonaws.com
```
### デプロイ
- この状態でもう一度デプロイして見ます。今回は２回目なので`eb deploy`コマンドを使います。

```
eb deploy
```
- しばらく待ちます。
- これで、正しくdeployが行われれば、`eb open`でサイトが見れるはずです。

```
eb open
```
- うまくできない場合は、`eb logs`でエラーを確認してGoogle先生等に聞いてエラーを解消してあげてください。
- 以上で、初期セットアップは終わりです。以下は開発上のTips的な記述ですので、必要に応じて参考にしていただければと思います。

# Tips
## Application Versionが規定数を超えていてデプロイできない場合
```
ERROR: You cannot have more than 500 Application Versions. Either remove some Application Versions or request a limit increase.
```
- AWSコンソールから作業することもできますが、CLIで行う場合、`eb appversion`コマンドの`--delete`オプションで削除できますが、version-label（VersionLabel）を知らなければいけません。

```
aws elasticbeanstalk describe-application-versions --application-name your-application-name
```
- 上記コマンドを実行すると以下のようなJSONが得られます。（値は適当なものを入れています）

```
    [
        {
            "ApplicationName": "your-application-name",
            "Status": "UNPROCESSED",
            "VersionLabel": "app-000f-191111_112017",
            "Description": "hogefuga",
            "DateCreated": "2017-03-27T07:20:16.892Z",
            "DateUpdated": "2017-03-27T07:20:16.892Z",
            "SourceBundle": {
                "S3Bucket": "elasticbeanstalk-ap-northeast-1-100000000001",
                "S3Key": "your-application-name/app-000f-191111_112017.zip"
            }
        }
    ]
```
- 上記JSONのVersionLabelを指定して削除します。古いのが一番下に出てくるので、古いのから削除していけばいいでしょう。

```
eb appversion --delete app-000f-191111_112017
```
## 注意
以下より、.ebextensionsディレクトリの利用が書かれておりますが、ElasticBeanstalkのPlatformにAL2を利用する場合、.ebextensionsは利用できません。`.platform/hooks`や`.platform/confighooks`を利用してください。詳細は[こちら](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/platforms-linux-extend.html)をご覧ください。
また、`.platform/hooks`配下のスクリプトは、`eb deploy`コマンドでは実行されますが、環境変数の更新だけなどでは実行されません。その場合は、`.platform/confighooks`を利用してください。シンボリックリンクを貼っておくと良いでしょう。

```bash
cd .platform/confighooks/prebuild
ln -s ../../hooks/prebuild/01_hoge.sh 01_hoge.sh
```

## yarnを利用する場合
- yarnをinstallするためのコマンドを`.ebextensions`ディレクトリ配下に置きます。
- [webpackerのissue](https://github.com/rails/webpacker/issues/118)にconfigファイルを掲示してくれている方がいるので参考にしてください。
- 私の場合、deploy時に、yarnコマンドでトランスパイルを実行させています。
- トランスパイル実行後にassets:precompileを走らせているので、`RAILS_SKIP_ASSET_COMPILATION`の環境変数は`true`にしてassets:precompileを実行させないようにし、.ebextensions内で実行しています。

```yml:.ebextensions/10_yarn.config
# see https://gist.github.com/yuyasat/dcc2f2214f5087833aca2069e69f92fb
```
```yml:.ebextensions/11_container_commands.config
container_commands:
  11-npm_install_build:
    command: cd frontend && sudo yarn install && sudo yarn release
  23-assets_precompile:
    command: bundle exec rake assets:precompile
```

## https接続する場合
- 流れとしては、
    - ドメインの取得
    - 証明書の発行（AWS Cetrificate Manager（ACM）、Let's encryptなどを利用する）
    - 証明書のLoadBalancerやEC2への紐付け
- [Clasic Load Balancer](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/using-features.managing.elb.html)の場合
    - `.ebextensions/loadbalancer-terminatehttps.config`が参考になります。
- [Application Load Balancer の設定](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/environments-cfg-applicationloadbalancer.html)の場合
    - `.ebextensions/alb-secure-listener.config`が参考になります。[こちらの記事](https://qiita.com/Mic-U/items/f7981cf82b4649247d55)も大変参考になりました。
- [ネットワークロードバランサー の設定](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/environments-cfg-nlb.html)の場合
    - ` .ebextensions/nlb-secure-listener.config`が参考になります。ただし、NLBの場合、SSLの終端がEC2になります。2018/4/6現在、ACMはEC2に適応できないため、ほかの方法を利用する必要があります。
- ACMでサブドメインのあり・なし共に利用できるワイルドカード証明書を作成する場合は、「ドメイン名の追加」において、`*.hogehoge.com`と`hogehoge.com`の二つを入力する必要があります。[こちら](http://tech.innovator.jp.net/entry/2017/02/22/130159)が詳しいです。
- httpをhttpsへリダイレクトする場合、ELBで80番ポートで受け取り、EC2（nginx）に81番ポートにフォワードし、nginx側で81番ポートにきた場合は、httpsにリダイレクトをする処理をかけるのがシンプルです。この手法は、Clasic Load BalancerとApplication Load Balancerで利用できます。
    - 81番ポートの手法を使わなくても[Gist](https://gist.github.com/yuyasat/f081d89d7497f7e30544a7738c2c4fc7)に載せたように、`/etc/nginx/conf.d/webapp_healthd.conf`をカスタマイズしても良さそうです。いろんなところでよく見るnginxのconfです。最終的に私のElasticBeanstalkの`01_nginx.conf`と`02_load-balancer.config`はGistに載せたような形になりました。

## EC2のタイムゾーンを変更する場合
- 初期はUTCになっています。

```bash
$ date
2018年  5月 23日 水曜日 01:22:22 UTC
```

- .ebextensionsの中にJSTに変える処理を追加します。

```yml:.ebextensions/01_timezone.config
commands:
  timezone-change:
    command: sed -i -e "s/UTC/Japan/g" /etc/sysconfig/clock
    ignoreErrors: false
  localtime-change:
    command: ln -sf /usr/share/zoneinfo/Japan /etc/localtime
    ignoreErrors: false
```

## `git`コマンドを入れる
 - 例えば`Gemfile`に`gem 'elasticsearch-rails', github: 'elastic/elasticsearch-rails', branch: '6.x'`のように`git`コマンドがないと`bundle install`ができない場合、入れる必要があります。
 - .ebextensionsの中に以下のような設定を行います。

```yml:.ebextensions/00_packages.config
packages:
  yum:
    git: []
```

## cronでrails runnerやrakeタスクを動かす
- cronでrails runnerやrakeタスクを実行したい場合、Elastic BeanstalkのWorker tierを用いれば良いのですが、そこまでするほどではない（orなるべく安く済ませたい）とき、.ebextensionsの中にcronの設定をしてあげる必要があります。
- そのとき、単純に`cd /var/app/current && rake -vT`などと書いたのでは動きません。Rails用の環境変数などが読み込まれていないからです。（[参考](https://stackoverflow.com/questions/20117626/crontab-in-amazon-elastic-beanstalk)）
    - 環境変数を読み込む
    - `/var/app/current`にディレクトリを移動する
    - `bundle`コマンドや`rails`コマンドをフルパスで指定して実行する
- コマンドが少し長くなってしまうので、下記では[AWSのドキュメント](https://aws.amazon.com/premiumsupport/knowledge-center/cron-job-elastic-beanstalk/)にならい、シェルスクリプトを実行させる形にしてあります。

```yml:.ebextensions/12_cronjob.config
files:
    "/etc/cron.d/mycron":
        mode: "000644"
        owner: root
        group: root
        content: |
            */2 * * * * root /usr/local/bin/my_rails_runner.sh

    "/usr/local/bin/my_rails_runner.sh":
        mode: "000755"
        owner: root
        group: root
        content: |
            #!/bin/bash

            . /opt/elasticbeanstalk/support/envvars
            cd /var/app/current

            # rails runnerの場合
            # 使っているrubyのversionに合わせる。eb sshして確認すること。
            /opt/rubies/ruby-2.5.0/bin/bundle exec /opt/rubies/ruby-2.5.0/bin/rails runner "puts MyModel.count" >> /var/log/cron-error.log 2>&1

            # rakeタスクの場合
            # /opt/rubies/ruby-2.5.0/bin/bundle exec /opt/rubies/ruby-2.5.0/bin/rake -vT >> /var/log/cron-error.log 2>&1

            exit 0

commands:
    remove_old_cron:
        command: "rm -f /etc/cron.d/*.bak"
```
## CircleCIから`eb deploy`コマンドを利用する
- CircleCIの `PERMISSIONS` > `AWS Permissions`でAWS IAMユーザのAcces KEY IDとSecret Access Keyをセットします。CircleCI用に権限を絞ったIAMユーザを用意しておくと良いでしょう。
- `.elasticbeanstalk/config.global.yaml`を用意する必要があるが、値を手動でセットするのは面倒なので、CircleCIにsshして`eb init`コマンドを叩くと`.elasticbeanstalk/config.yaml`が吐き出されるので、それをコピーすると楽です。
- `.circleci/config.yml`にはebコマンドのインストールとDeployの実行を追加します。

```yaml:.circleci/config.yml
 - run:
     name: Install eb Command
     command: |
       if [[ $CIRCLE_BRANCH = master && $CIRCLE_NODE_INDEX -eq 0 ]]; then
         sudo apt-get -y -qq update
         sudo apt-get install python-pip python-dev build-essential
         sudo pip install awsebcli --upgrade
       fi
 - run:
     name: Deploy Staging
     command: |
       if [[ $CIRCLE_BRANCH = master && $CIRCLE_NODE_INDEX -eq 0 ]]; then
         eb deploy your-envorinment-name
       fi
```

## assets:precompileについて
 - ElasticBeanstalkを使っていると、`assets:precompile`が遅くなるという問題が生じることがあります。ローカルで`assets:precompile`実行したらすぐに終わるのに、ElasticBeanstalkのEC2上で実行するととても時間がかかってしまうということがあります。この原因は、t2やt3系を使っているとCPU負荷が上がってきたときにバーストしてくれますが、これは言い換えれば普段はCPU処理能力が低いということを意味します。`assets:precompile`実行時には多くのCPU処理能力が求められますから、CPU処理能力が低いと`assets:precompile`は非常に遅くなってしまいます。t2やt3系の場合バーストしてくれてCPU処理能力は上がっていきますが、少なくとも一つのコアはつねに100%を保ちながら処理を続けることになります。したがって、t2.smallなどのコア数が１のインスタンスを使っているとその状態でアクセスが来ると処理能力を超えサーバーが落ちてしまいます。（確か503 Service Temporarily Unavailableになります）
 - それを回避するには、バーストしない（通常からCPU処理能力が高い）EC2インスタンスタイプを利用するか、`assets:precompile`をEC2上で行わないようにします。
 - 私の場合、CircleCIを利用しているので、CircleCI上で`assets:precompile`を走らせS3に上げ、それをデプロイ時にsyncするという方式をとっています。
 - まず、忘れずに環境変数`RAILS_SKIP_ASSET_COMPILATION`には`true`をセットしておきます。
 - 以下のような形で`.circleci/config.yml`に`assets:precompile`を行い、s3におきます。

```yml:.circleci/config.yml
      - run:
          name: Install aws command
          command: |
            if [[ $CIRCLE_BRANCH = master && $CIRCLE_NODE_INDEX -eq 0 ]]; then
              wget https://bootstrap.pypa.io/get-pip.py
              sudo python get-pip.py
              sudo apt-get install python-dev
              sudo pip install awscli
            fi
      - run:
          name: Execute Assets Precompile and s3 sync
          command: |
            if [[ $CIRCLE_BRANCH = master && $CIRCLE_NODE_INDEX -eq 0 ]]; then
              bundle exec rake assets:precompile
              aws s3 sync public/assets/ s3://hogehoge/fugafuga/assets
            fi
```
 - 加えて、deploy時のコマンドでassetsをdownloadします。また、sprockets-manifestも不要なものは削除するコマンドを実行します。

```yml:.ebextensions/10_container_commands.config
container_commands:
  10-download_assets:
    command: sudo aws s3 cp s3://$RACK_DEV_MARK_ENV-summit-oem/front/public/assets/ public/assets/ --recursive
  11-remove_old_manifest:
    command: ls -1t public/assets/.sprockets-manifest-*.json | awk 'NR > 1 {print}' | xargs -r sudo rm
```
 - もっと良い方法がありましたら教えてください。

## AmazonLinux2（AL2）で環境変数が読み込まれない場合
- `/opt/elasticbeanstalk/deployment/env` に記載のある環境変数を読み込む必要がある。
```
sudo su
export $(sudo cat /opt/elasticbeanstalk/deployment/env)
```

## はまりポイント
- アプリケーションを起動させるのに環境変数を正しく設定する必要がある場合があります。しかし、`eb setenv`コマンドをつかっても、画面の`設定`->`ソフトウェアの変更`から変更してもエラーになって反映されない・・・！
    - 私のケースの場合、`ヘルスチェックに合格しなくてもデプロイに失敗しない。`にチェックが入っており、アプリケーション側でエラーになってヘルスチェックが通らず、設定も反映されない状態でした。
    - `ローリング更新とデプロイの変更`->`ヘルスチェックを無視`にチェックを入れてヘルスチェックが通らない場合でも無視するように変更する。
- 初期構築の際、トライアンドエラーを繰り返すことがあるかと思います。その時に、実行終了までに時間がかかってしまうことがあります。こういう場合は、`ローリング更新とデプロイの変更`->`コマンドタイムアウト`の値を減らすことも一つの方法です。デフォルトでは600（10分）になっていると思いますが、初期構築時には300（5分）にしても大きな問題とならないでしょう。
- デバッグの方法
    - sshしてEC2インスタンス内でlogを見ると捗ります。個人的によく使うのは以下のようなコマンドです。

```bash
$ tail -f -n500 /var/log/eb-activity.log # eb-activity.logを監視（AmazonLinux２では、eb-engine.logになります）
$ tail -f -n500 /var/log/nginx/error.log # nginxのerror.logを監視
$ tail -f -n500 /var/log/puma/puma.log # puma.logを監視
$ tail -f /var/log/*.log /var/log/**/*.log # /var/log配下のログファイルを全て監視
$ top -c # プロセスやCPU使用率などを確認
$ ps aux | sort -n -k 3 | tail -n10 # 具体的なプロセスを確認。-nで数値で並び替え、-kで3列目（CPU%）で並び替え対象列。
```
- `/var/log/nginx/error.log`で次のようなerrorが出る場合
    - puma/my_app.sockに接続できないよと言う意味です。
    - 自力で構築するときはやりようがありますが、ElasticBeanstalkの場合どうすれば良いかよくわからないので、EC2インスタンスを再起動すればうまくいくことがあります。再起動でもうまくいかない場合、Terminate（終了）して別のインスタンスと立ち上げるとうまくいきやすいです。

```
2018/09/10 19:25:54 [error] 1153#0: *313953 connect() to unix:///var/run/puma/my_app.sock failed (111: Connection refused) while connecting to upstream, client: 172.32.22.222, server: _, request: "GET /healthcheck HTTP/1.1", upstream: "http://unix:///var/run/puma/my_app.sock:/healthcheck", host: "172.32.22.222"
```
## よく使うコマンド
- 環境名（以下、environment-name)一覧を取得したい時

```
eb list
eb list --profile default # profile名を指定する場合
# profile名は、cat ~/.aws/credentialsで確認できます。
```
- deployする時（ブランチにデフォルトの環境名を設定することもできますが、環境名を指定してdeployすることの方が多いです）

```
eb deploy environment-name # envorinment-nameは個々の環境名
eb deploy environment-name --profile default # profile名を指定する場合
```
- セットされている環境変数を知る時

```
eb printenv environment-name
```
- 環境変数をセットする時

```
eb setenv PGHOST=xxxxxxxxx -e envorinment-name
```
- EC2にsshする時

```
eb ssh envorinment-name
cd /var/app/current/ # Rails.rootへ。
bin/rails console # Rails consoleを起動。
# 上記コマンドでlog/*.logにアクセス権限がないと言われてしまう場合chmodで権限を変更するか、rootユーザーになって行う。
sudo su # rootユーザになる
bin/rails console
```

# 最後に
- Elastic Beanstalkをやる前に、自分でELBを用意し、EC2インスタンスを作成し、nginxを立て、unicornの設定をし・・・といった作業をして環境を構築していました。Elastic Beanstalkはこのあたりを鮮やかにブラックボックス化してくれているという印象を受けました。インフラ力を高めたい場合には、こうした便利ツールを使わずに、自分の手で一つ一つやっていったほうが良いと思います。（オンプレ世代からみると、AWSもかなりの便利ツールではありますが・・・。）
- 情報には万全を期していますが、一通り作業をした後メモを元に書いているので、抜け漏れがあるかと思います。コメントや編集などで`やさしく`ご指摘いただけますと幸いです。

# 参考
1. [AWS Elastic Beanstalk ドキュメント](https://aws.amazon.com/jp/documentation/elasticbeanstalk/)
1. [EB CLI 3.x を使って Elastic Beanstalk に Rails アプリをデプロイする](http://xyk.hatenablog.com/entry/2015/02/13/163657)
2. [AWS Elastic Beanstalk に Rails を構築する手順。](http://qiita.com/jr_qrank/items/aadc076ebf93a2692d14)
3. [ebコマンドを使ってElasticBeanstalkでデプロイしてみる](http://qiita.com/toshihirock/items/593e17d42a8d1d533a49)
4. [describe-environments &mdash; AWS CLI 1.11.158 Command Reference](http://docs.aws.amazon.com/cli/latest/reference/elasticbeanstalk/describe-environments.html)
5. [AWS Elastic Beanstalk x Ruby on Rails で構築する](http://unching-star.hatenablog.jp/entry/2016/10/06/142009)
6. [それではElastic Beanstalkの本気をお見せしよう](https://qiita.com/Mic-U/items/f7981cf82b4649247d55)