AL2023内のElastic Beanstalk環境でbundle exec rails c (rails console) する方法

# 結論

```ruby
gem 'irb', require: false
```

がある状態で、

```bash
eb ssh
```

して、`rails c`するならこう。
```bash
sudo su -c 'env $(cat /opt/elasticbeanstalk/deployment/env | xargs) su webapp -c "cd /var/app/current ; bundle exec rails c"'
```

じゃなくて必要な環境変数を持った状態で`webapp`ユーザになるだけならこう。
```bash
sudo su -c 'env $(cat /opt/elasticbeanstalk/deployment/env | xargs) su webapp'
```

# Gemfileについて
ここはちょっと自信がない部分。
Ruby2.5までは明示しなくても`irb`が利用できたけど、2.6以降はGem化されたらしく、使用するのであれば明示的に書いておく必要があるらしい。
ただ、アプリケーションとして必要なわけではないことが多いはずなので、`require: false`としています。

# コマンドの説明

[以前までの手順](https://qiita.com/edg_aim/items/3f81efe9ee98c417df73)よりも大幅ブラッシュアップのワンライナーで登場です。
以前のものも同様に書き換えることはできるんですが、今後需要がなくなって行くと思うのでそのままにしておきます。

ちなみにAL2では`rbenv`で`ruby`のバージョンが管理されていましたがAL2023では`alternatives`になったようです。
なんでなのかは謎です。

あ、`eb ssh`については説明しませんのであしからず。

要素を分解していくと案外簡単な構造です。

```bash
sudo su -c 'XXX`
```
AL2023にログインした直後の`ec2-user`は直接`su`を実行できないので、`sudo`を経由して`su`を実行しています。
ユーザを省略しているので`root`ユーザになろうとしています。
`-c 'XXX'`は指定ユーザで`XXX`を実行するというオプションになります。

`XXX`部分は少々長く、
```bash
env $(cat /opt/elasticbeanstalk/deployment/env | xargs) su webapp -c "cd /var/app/current ; bundle exec rails c"
```
となっていますが、展開後の構文的には
```bash
env A=1 B=2 C=3 su webapp -c "YYY"
```
のような形になっていて、環境変数を指定しつつコマンドの実行をしています。
実行しているコマンドは先程とほぼ同じですが、`webapp`ユーザでコマンド`YYY`を実行することになります。

環境変数の部分は直接コマンドを入力する場合には`env`がなくても問題ありませんが、コマンド実行した結果の展開（`$()`）を利用するため、明示する必要があります（多分）

`/opt/elasticbeanstalk/deployment/env`にはElastic Beanstalk環境に設定されている環境変数が1行に1つずつ
```text
A=1
B=2
C=3
```
のような形で定義されています。
これを`cat`して`xargs`を通すことで
```bash
cat /opt/elasticbeanstalk/deployment/env | xargs
```
```text
A=1 B=2 C=3
```
という結果を得ることができます。

最後の`YYY`部分については簡単です。
```bash
cd /var/app/current ; bundle exec rails c
```
コマンドの連続実行になっていますが、アプリケーションルートに移動し、`rails c`です。

- `root`ユーザで
    - 環境変数を設定しつつ
    - `webapp`ユーザで
        - アプリケーションを実行

という感じですね。

# Railsが起動するまでの流れ

できる限り本来のアプリケーションが起動するのと同じものを利用して`rails c`したかったのでなんとなーく、動作を追ってみたのでその記録として。
一部、想像も入ってます。

## Procfile

[アプリケーションルートのProcfile](https://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/ruby-platform-procfile.html)が使われます。
存在しない場合はデフォルト設定で起動するようですが、デフォルト設定はEBとして動作確認されているので同じ内容にしています。

```text:/var/app/current/Procfile
web: bundle exec puma -C /opt/elasticbeanstalk/config/private/pumaconf.rb
```

## systemctlのweb.service

おそらくProcfileを元にしてこのファイルが作られてる・・・と思います。
Procfileの`process type`に指定してある部分を持ってきて`XXX.service`に、起動用の`command`部分を`ExecStart=/bin/sh -c "XXX"`部分に埋め込んでる・・・んじゃないかな・・・
で、この中で実行ユーザが`webapp`であり、環境変数が記載されたファイルは`/opt/elasticbeanstalk/deployment/env`であることが明示されています。

```text:/etc/systemd/system/web.service
[Unit]
Description=This is web daemon
PartOf=eb-app.target

[Service]
User=webapp
Type=simple

ExecStart=/bin/sh -c "bundle exec puma -C /opt/elasticbeanstalk/config/private/pumaconf.rb"

ExecStartPost=/bin/sh -c "systemctl show -p MainPID web.service | cut -d= -f2 > /var/pids/web.pid"
ExecStopPost=/bin/sh -c "rm -f /var/pids/web.pid"

Restart=always

EnvironmentFile=/opt/elasticbeanstalk/deployment/env

SyslogIdentifier=web
WorkingDirectory=/var/app/current/

[Install]
WantedBy=multi-user.target
```

## 環境変数

こんな感じでずらーっと書かれてます。

```text:/opt/elasticbeanstalk/deployment/env
RAILS_SKIP_MIGRATIONS=false
AWS_REGION=ap-northeast-1
BUNDLE_WITHOUT=test:development
:
:
```

## pumaconf.rb

でPumaの設定がこれ。
アプリケーションルートが`/var/app/current`であることが明示されてます。

```ruby:/opt/elasticbeanstalk/config/private/pumaconf.rb
directory '/var/app/current'
threads 8, 32
workers %x(grep -c processor /proc/cpuinfo)
bind 'unix:///var/run/puma/my_app.sock'
```

## config.ru

Pumaの設定に`rackup`の指定がないため、デフォルトの`config.ru`が参照され、ここからRuby・・・というかRailsが起動を始めていきます。

```ruby:config.ru
# This file is used by Rack-based servers to start the application.

require_relative 'config/environment'

run Rails.application
```

# Amazon Linuxの表記揺れ吸収用
AmazonLinux
Amazon Linux
AL2
AmazonLinux2
AmazonLinux 2
Amazon Linux 2
AL2023
AmazonLinux2023
AmazonLinux 2023
Amazon Linux 2023