ENECHANGE Developer Blog

ENECHANGE開発者ブログ

AWS Elastic Beanstalk で使用される Ruby のバージョンを指定する方法と、それぞれの方法の特徴について

こんにちは。毎日 島の整備に忙しい ENECHANGE の gamenechange と申します。今回は AWS Elastic Beanstalk(以下、EB)において、使用される Ruby のバージョンを指定する方法および各方法の特徴について書かせて頂きます。

Rails アプリをデプロイしている前提となります。

準備: EB で使用される Ruby のバージョンを確認する

まず、EB で使用される Ruby のバージョンを確かめてみます。

次のように $ eb ssh を行ってから RUBY_VERSION を調べることで Ruby のバージョンを確かめることができます。root で実行する必要があるので注意しましょう。

$ eb ssh
 _____ _           _   _      ____                       _        _ _
| ____| | __ _ ___| |_(_) ___| __ )  ___  __ _ _ __  ___| |_ __ _| | | __
|  _| | |/ _` / __| __| |/ __|  _ \ / _ \/ _` | '_ \/ __| __/ _` | | |/ /
| |___| | (_| \__ \ |_| | (__| |_) |  __/ (_| | | | \__ \ || (_| | |   <
|_____|_|\__,_|___/\__|_|\___|____/ \___|\__,_|_| |_|___/\__\__,_|_|_|\_\
                                       Amazon Linux AMI
$ sudo su
# cd /var/app/current
# bin/rails console
Loading production environment (Rails 6.0.1)
irb(main):001:0> RUBY_VERSION
=> "2.6.4"

EB で用いられる Ruby のバージョンはどこで指定するのか

上記の例では、EB で用いられている Ruby のバージョンは 2.6.4 です。この Ruby のバージョンはどこで指定するのでしょうか。

指定に際しては以下の2つの方法があります。

1. Gemfile 内で指定する

Gemfile 内で ruby '2.6.5' のように記述すると*1$ bundle install を行った際に Gemfile.lock に Ruby のバージョン情報が記載されます。

Gemfile
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.6.5'
Gemfile.lock
RUBY VERSION
   ruby 2.6.5p114

これらのファイルを含んで EB にデプロイすると、Gemfile 内で記述したバージョンが使用されます。

2. EB の Platform がサポートするバージョンを用いる

1. では Gemfile 内に Ruby のバージョンを記述することで、EB での Ruby のバージョンを指定しました。一方でこの記述を削除することで、「EB の Platform がサポートする Ruby のバージョン(後述)」を用いることができます。

具体的には、Gemfile から ruby '2.6.5' の行を削除し、$ bundle install をして、EB にデプロイします。すると、EB の Platform がサポートしている Ruby のバージョンが、使用される Ruby のバージョンになります。

どのバージョンの Platform がどのバージョンの Ruby をサポートしているかについては次の公式ドキュメントをご覧ください。

docs.aws.amazon.com

EB へのデプロイが失敗するケース

EB での Ruby のバージョンを指定する方法は上記のとおりです。いずれの方法を用いるにしろ狙いどおりにデプロイが成功すれば問題ないのですが、「1. Gemfile 内で指定する」の場合は特定の状況ではデプロイに失敗します。

どのような状況で失敗するかというと、「デプロイ先の EB の Platform が、Gemfile に記述した Ruby のバージョンをサポートしていない場合」です。

以下に例を挙げます。Gemfile 内では 2.6.4 を指定しているところ、Platform 側で対応しているバージョンが 2.6.5 のケースです。

$ eb deploy
Creating application version archive "XXXXXXXXXX".
Uploading XXXXXXXXXX.zip to S3. This may take a while. 
Upload Complete.
2020-03-26 06:57:15    INFO    Environment update is starting.
2020-03-26 06:58:00    INFO    Deploying new version to instance(s).
+ bundle install
Your Ruby version is 2.6.5, but your Gemfile specified 2.6.4.
2020-03-26 06:58:17    ERROR   Failed to deploy application.

ERROR: ServiceError - Failed to deploy application.

それぞれの方法のメリットとデメリット

上記の2つの方法を用いる際のメリットとデメリットを考えてみます。

「1. Gemfile 内で指定する」場合のメリットとデメリット

メリット

「1. Gemfile 内で指定する」場合のメリットは、「指定したバージョンでデプロイされることが保証されること」です。前述のように、EB の Platform 上での Ruby のバージョンと Gemfile での Ruby のバージョンが完全一致しない場合にはデプロイが失敗します。したがって、意図しないバージョンが実行されることがありません。

また、EB の Platform の自動アップデートにもちゃんと失敗してくれますので、その点でも意図しないバージョンが使われることがありません。

gyazo.com

デメリット

上記のメリットはデメリットにもなります。つまり、Ruby のバージョンを上げる場合には Gemfile の記述を変更することはもちろん、EB の Platform も対応している Platform のバージョンにアップグレードする必要があるということです。Gemfile の記述の変更は容易ですが、Platform のバージョンをアップグレードすることは簡単ではない場合も多いでしょう。

また、環境を作り直した際などに Platform のバージョンが意図せず上がってしまった場合には、バージョンの不一致によりデプロイに失敗することがあります。

「2. EB の Platform がサポートするバージョンを用いる」場合のメリットとデメリット

メリット

「2. EB の Platform がサポートするバージョンを用いる」場合のメリットは、開発者は Ruby のバージョンを意識する必要がない、という点です*2

デメリット

他方、デメリットは「開発環境と EB 側の環境で Ruby のバージョンが異なる場合がある」ことです。

開発環境で用いる Ruby のバージョンは .ruby-version で指定すると思います*3。しかし、EB で用いられる Ruby のバージョンは Platform がサポートするバージョンです*4

開発環境で用いているバージョン*5と EB で使用されるバージョンが異なる場合でも、Gemfile 内で Ruby のバージョンの指定はしていませんので、デプロイに失敗することはありません。その結果、開発環境と EB 側の環境で意図しないバージョンの相違が起きる可能性があります。

一つの例としては、EB の Platform の自動アップデートを有効にしている場合です。Platform の自動アップデートが有効の場合は、Platform がアップデートされた際にサポートする Ruby のバージョンも自動で上がっていきます。そうなったとしてもデプロイは失敗しないため、開発環境とのバージョンの差分が発生している可能性があります*6。差分をなくすためには、適宜 .ruby-version を更新していく必要があります。

もう一つの相違が起きる例としては、.ruby-version をアップグレードして開発をする場合です。この場合、アップグレードしたバージョンが EB 側では使われないケースがあります*7.ruby-version を書き換えても、EB 側のバージョンには影響がないからです*8。この場合は .ruby-version のバージョンに合致するように Platform をアップグレードする必要があります。

どちらの方法で Ruby のバージョンを指定すればいいのか

ではどちらの方法で Ruby のバージョンを指定すればいいのでしょうか。結論から言うと、アプリやプロダクトの方針によると思います。

Ruby のバージョンをガッチリと固定して厳格に運用したい場合には「1.」の方法を採ることになるでしょう。ただし、バージョンアップ時のコストがかかりますし、開発者間でのEBの知見の共有も必要でしょう。いざというときにデプロイ自体が成功しない可能性があるということは、少なからず怖いものです。

他方、そこまで厳格に運用する必要性がない場合には「2.」の方法を採ることになるでしょう。.ruby-version を適宜更新していく必要がありますが、特段の意識をせずに誰でも EB にデプロイすることができます。

ENECHANGE株式会社ではエネルギーの未来を作る仲間を募集しています

ENECHANGE株式会社では、EBの問題からエネルギーの問題まで、幅広く解決をしたいエンジニアを募集しております。詳しくは採用情報のページをご覧ください。

enechange.co.jp

参考: EB にインストールされている Ruby のバージョンを確認する方法

EB にインストールされている Ruby のバージョンを確認するためには、$ eb ssh をした後に、/opt/rubies 配下を見てみましょう。

$ eb ssh
 _____ _           _   _      ____                       _        _ _
| ____| | __ _ ___| |_(_) ___| __ )  ___  __ _ _ __  ___| |_ __ _| | | __
|  _| | |/ _` / __| __| |/ __|  _ \ / _ \/ _` | '_ \/ __| __/ _` | | |/ /
| |___| | (_| \__ \ |_| | (__| |_) |  __/ (_| | | | \__ \ || (_| | |   <
|_____|_|\__,_|___/\__|_|\___|____/ \___|\__,_|_| |_|___/\__\__,_|_|_|\_\
                                       Amazon Linux AMI
$ cd /opt/rubies
$ ls -la
合計 40
drwxr-xr-x 10 root root 4096  3月 27 08:31 .
drwxr-xr-x  6 root root 4096  3月 27 08:31 ..
drwxr-xr-x  6 root root 4096 10月 13  2017 ruby-1.9.3-p551
drwxr-xr-x  6 root root 4096 10月 13  2017 ruby-2.0.0-p648
drwxr-xr-x  6 root root 4096 10月 13  2017 ruby-2.1.10
drwxr-xr-x  6 root root 4096  4月 12  2018 ruby-2.2.10
drwxr-xr-x  6 root root 4096 10月 19  2018 ruby-2.3.8
drwxr-xr-x  6 root root 4096 10月  3 20:39 ruby-2.4.9
drwxr-xr-x  6 root root 4096 10月  3 20:35 ruby-2.5.7
drwxr-xr-x  6 root root 4096 10月  3 20:31 ruby-2.6.5
lrwxrwxrwx  1 root root   22  3月 27 08:31 ruby-current -> /opt/rubies/ruby-2.6.5

*1:$ rails new した場合にデフォルトで記述されています

*2:厳密には意識しなければいけない場面はあります

*3:rbenvを用いる場合。以下同様です

*4:.ruby-version は参照されない

*5:.ruby-version

*6:EBの方がバージョンが上になっている

*7:=開発環境のみで使われる

*8:=開発環境の方がバージョンが上になっている