最近になって Ruby on Jets というサーバレスフレームワークを知る機会があり、面白そうだったので触ってみました。Ruby on Jets は Rails ライクな開発ができるフレームワークで、それを AWS Lambda の Ruby Runtime の Function としてデプロイできるサーバレスなフレームワークです。
環境としてはローカルのPCで開発する場合は Lambda にデプロイする際に AWS アカウントの認証が必要になりますが、 Cloud9 環境であればシームレスに AWS サービスと連携できるので、今回は Cloud9 環境で試してみます。Ruby on Jets にはチュートリアル的に Quick Start が用意されているので、これを一通り試してみます。
環境構築
Cloud9 自体の環境構築については今回は割愛しますので、よろしければこちらをご参照ください。
まず Ruby ですが、 Ruby on Jets は 2020/3/27 現在では Ruby 2.5系までの対応となっていますので、2.5系の最新版である 2.5.7 を使用します。
$ ruby -v ruby 2.5.7p206 (2019-10-01 revision 67816) [x86_64-linux]
ちなみに Ruby 2.6 以降を使っているとローカルで開発している段階では問題なくても、 Lambda への deploy 時に下記のように怒られてしまいます。
You are using Ruby version 2.7.0 which is not supported by Jets. Jets uses Ruby 2.5.3. You should use a variant of Ruby 2.5.x
Jets では Rails 同様に bundler を使用しますので、インストールしておきます。
$ rbenv exec gem install bundler Fetching: bundler-2.1.4.gem (100%) Successfully installed bundler-2.1.4 1 gem installed $ $ rbenv exec gem which bundler /home/ec2-user/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/bundler-2.1.4/lib/bundler.rb
そして Jets をインストールします。
$ rbenv exec gem install jets
下記のようにインストールされたことが確認できます。
$ rbenv exec gem which jets /home/ec2-user/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/jets-2.3.14/lib/jets.rb $ $ rbenv exec jets -v 2.3.14
また、 Jets では yarn を使用していますのでインストールします。
$ npm install -g yarn /home/ec2-user/.nvm/versions/node/v10.19.0/bin/yarn -> /home/ec2-user/.nvm/versions/node/v10.19.0/lib/node_modules/yarn/bin/yarn.js /home/ec2-user/.nvm/versions/node/v10.19.0/bin/yarnpkg -> /home/ec2-user/.nvm/versions/node/v10.19.0/lib/node_modules/yarn/bin/yarn.js + yarn@1.22.4 added 1 package in 0.445s
今回 DB に MySQL互換の Aurora を使用しますので、下記ライブラリをインストールしておきます。
$ sudo yum install mysql-devel
プロジェクト作成
Jets では Rails 同様に new コマンドでプロジェクトを作成できます。 Database Adopter はデフォルトで MySQL が選択されます。
$ rbenv exec jets new demo
これで素のプロジェクトが作成されましたので、ひとまずサーバを起動して動作することを確認してみます。デフォルトでは 8888 ポートが使用されますが、 Cloud9 のプレビューで動作確認する場合、対応しているポートが 8080、8081、8082 なので、ポート番号を指定して起動します。
$ cd demo/ $ rbenv exec jets server --port 8080 〜〜〜中略〜〜〜 warning package.json: No license field warning No license field => bundle exec rackup --port 8080 --host 127.0.0.1 Jets booting up in development mode! [DEPRECATED] `Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env` (called at /home/ec2-user/.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/jets-2.3.14/lib/jets/commands/main.rb:46) warning package.json: No license field warning No license field Puma starting in single mode... * Version 4.3.3 (ruby 2.5.7-p206), codename: Mysterious Traveller * Min threads: 0, max threads: 16 * Environment: development * Listening on tcp://127.0.0.1:8080 Use Ctrl-C to stop
Cloud9 の IDE 画面から Preview を実行します。
下記のように Jets の画面が表示されれば Jets が起動できています。
Scaffold での確認
今回はとりあえず動作確認ができれば良いので、 Scaffold を試してみます。今回 DB は Aurora を使用しますので、 まずは RDS のコンソールから下記のような内容で DB を作成します。
このままだと DB と同じ VPC の中からしか接続できないので、VPC セキュリティグループのインバウンドルールを変更します。最初は下記画像の上段のようになっていますので、とりあえず今回は試すだけということでどこからでも接続できるように下段のような内容に変更します。
設定を変更したら Cloud9 のターミナルから接続できることを確認します。
$ mysql -h ruby-on-jets-demo.cluster-cnxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com -u admin -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 37 Server version: 5.6.10 MySQL Community Server (GPL) Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
ひとまずこれで DB の準備ができたので、下記コマンドで Scaffold を作成します。
$ rbenv exec jets generate scaffold post title:string
DB の接続先情報については環境設定ファイル .env.development
に下記のように設定します。
$ vi .env.development $ cat .env.development # Example .env.development, meant to be updated. ENV_DEVELOPMENT_KEY=example1 DATABASE_URL=mysql2://admin:xxxxxxxx@ruby-on-jets-demo-instance-1.cnxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com/demo_development?pool=5
migrate を実行して Database とテーブルを作成します。
$ rbenv exec jets db:create db:migrate
Aurora の方で確認すると下記のように posts
テーブルが作成されています。
mysql> show tables; +----------------------------+ | Tables_in_demo_development | +----------------------------+ | ar_internal_metadata | | posts | | schema_migrations | +----------------------------+ 3 rows in set (0.01 sec)
サーバを起動して動作を確認してみます。
$ rbenv exec jets server --port=8080
先ほどと同様に Cloud9 の Preview でアクセスしてみます。 /posts
にアクセスすると下記のように posts の CRUD が行えるようになっています。
画面から posts の作成や変更が行えていればOKです。
Aurora でも確認してみます。下記のように posts のレコードが作成されています。
mysql> select * from posts; +----+-------+----------------------------+----------------------------+ | id | title | created_at | updated_at | +----+-------+----------------------------+----------------------------+ | 1 | Test1 | 2020-03-26 00:13:46.882807 | 2020-03-26 00:13:46.882807 | | 2 | Test2 | 2020-03-26 00:13:54.803820 | 2020-03-26 00:13:54.803820 | +----+-------+----------------------------+----------------------------+ 2 rows in set (0.00 sec)
Lambda にデプロイする
ローカルでの確認がひとまず終わりましたので、 Lambda 環境へデプロイしてみます。Quick Start に記載されている手順通りにここまでやってくると、私が試した時点では nokogiri の 1.10.9 が使われるのですが、このまま Lambda 環境へデプロイしてアクセスすると下記のようなエラーが出てしまいました。
"errorMessage": "Could not find nokogiri-1.10.9 in any of the sources", "errorType": "Init<Bundler::GemNotFound>",
調べた結果これは nokogiri のバージョンによるもののようで、 1.10.8 を使えば回避できそうでしたので、 Gemfile に下記の設定を追加します。
gem 'nokogiri', '1.10.8'
bundle update
で gem を更新します。
$ rbenv exec bundle update nokogiri
ローカルでの動作時は環境設定に .env.development
というファイルを使用していましたが、 deploy 時は .env.development.remote
が使用されますので、ファイルを作成します。DB のホストはローカルと同じ Aurora を使用し、 DB名だけ変更してみます。
$ cp .env.development .env.development.remote $ vi .env.development.remote $ diff .env.development .env.development.remote 3c3 < DATABASE_URL=mysql2://admin:xxxxxxxx@ruby-on-jets-demo-instance-1.cnxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com/demo_development?pool=5 --- > DATABASE_URL=mysql2://admin:xxxxxxxx@ruby-on-jets-demo-instance-1.cnxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com/demo_development_remote?pool=5
DB の migrate を実行します。環境変数として JETS_ENV=development JETS_ENV_REMOTE=1
を設定することによって接続先情報として .env.development.remote
が参照されるようになります。
$ JETS_ENV=development JETS_ENV_REMOTE=1 bundle exec jets db:create db:migrate
Aurora で Database とテーブルが作成されたことを確認します。
mysql> show tables; +-----------------------------------+ | Tables_in_demo_development_remote | +-----------------------------------+ | ar_internal_metadata | | posts | | schema_migrations | +-----------------------------------+ 3 rows in set (0.00 sec)
これで deploy する準備ができましたので、 deploy コマンドを実行します。
$ bundle exec jets deploy
実行途中で下記のように gem を Lambdagems に送って良いか聞かれますので、Y
と答えて処理を続行します。 nokogiri などのネイティブ拡張を使ってコンパイルされるような gem は、ローカルでコンパイルしたものをそのまま Lambda に配置しても使用できませんので、 Jets は Lambdagems からプリコンパイルされた gem をダウンロードして使用するようです。
Is it okay to send your gem data to Lambdagems? (Y/n)? Y
deploy に成功すると下記のようにアクセス先の URL が表示されます。
Stack success status: UPDATE_COMPLETE Time took for stack deployment: 1m 32s. Prewarming application. API Gateway Endpoint: https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/
ブラウザから上記のURLにアクセスしてローカルでプレビューした時と同様に jets の画面が表示され、 /posts
で posts の CRUD が行えれば正しく deploy されています。
Lambda のコンソールから確認すると、下記のように Lambda Function が作成されています。
また、 API Gateway の下記のように自動的に作成されています。
まとめ
今回はひとまず Quick Start の内容を一通り試してみただけですが、ローカルでは Rails ライクに開発することができ、 Lambda のことを意識しなくても deploy すれば自動的に Lambda Function を構成してくれますので、手軽に Serverless なサーバサイド開発が行えました。 Cloud9 であれば AWS サービス利用時の認証等の手間もありませんので、とても相性よく使えると思います。 Ruby on Jets はまだプロダクション環境での実績はあまりないようですが、 Serverless な構成ができると実運用でのメンテナンスやスケーリングのコストもかなり削減できますので、いろいろ試して将来的には実際のサービスに使えると良いなと思っています。