Ruby で Rails ライクにサーバーレスアプリケーションが作れる Jets を使ってみた

今回はRuby でサーバーレスアプリケーションが Railsライクで構築できる Jets を試してみました
2020.01.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

西田@大阪です

Rubyが好き人はいろいろなORMを使っていると、どうしてもActiveRecord が使いたくなる人もいるのではないでしょうか? 今回はRuby でサーバーレスアプリケーションが Railsライクで構築できる Jets を試してみました

tongueroo/jets: Ruby on Jets

試した環境

  • jets: 2.3.12

jestsは2.3.12時点では ruby 2.5.3 を要求するため、事前にインストールしておきます

$ rbenv install 2.5.3  
$ rbenv global 2.5.3

※ rbenv でのインストールコマンドです。試される場合はご自身の環境に合わせたコマンドでお使いください

Quick Start - Jets Ruby Serverless Framework に従い動かしてみたいと思います

インストール

Jetsをgemでインストールします

$ gem install jets

プロジェクトの作成

プロジェクトを作成します

$ jets new demo

# postgresqlを使用する場合は以下
$ jets new demo --database=postgresql

以下のファイルが生成されます

.                                                                                                                                                                                                                 
├── Gemfile                                                                                                                                                                                                       
├── Gemfile.lock                                                                                                                                                                                                  
├── Procfile                                                                                                                                                                                                      
├── README.md                                                                                                                                                                                                     
├── Rakefile                                                                                                                                                                                                      
├── app                                                                                                                                                                                                           
│   ├── controllers                                                                                                                                                                                               
│   │   └── application_controller.rb                                                                                                                                                                             
│   ├── helpers                                                                                                                                                                                                   
│   │   └── application_helper.rb                                                                                                                                                                                 
│   ├── javascript                                                                                                                                                                                                
│   │   ├── packs                                                                                                                                                                                                 
│   │   │   ├── application.js                                                                                                                                                                                    
│   │   │   └── theme.scss                                                                                                                                                                                        
│   │   └── src
│   │       └── jets
│   │           └── crud.js
│   ├── jobs
│   │   └── application_job.rb
│   ├── models
│   │   ├── application_item.rb
│   │   └── application_record.rb
│   └── views
│       └── layouts
│           └── application.html.erb
├── bin
│   ├── webpack
│   └── webpack-dev-server
├── config
│   ├── application.rb
│   ├── database.yml
│   ├── dynamodb.yml
│   ├── environments
│   │   ├── development.rb
│   │   ├── production.rb
│   │   └── test.rb
│   ├── routes.rb
│   ├── webpack
│   │   ├── development.js
│   │   ├── environment.js
│   │   ├── production.js
│   │   ├── staging.js
│   │   └── test.js
│   └── webpacker.yml
├── config.ru
├── db
├── package.json
├── public
│   ├── 404.html
│   ├── 422.html
│   ├── 500.html
│   ├── favicon.ico
│   └── index.html
├── spec
│   ├── controllers
│   │   └── posts_controller_spec.rb
│   ├── fixtures
│   │   └── payloads
│   │       ├── posts-index.json
│   │       └── posts-show.json
│   └── spec_helper.rb
└── yarn.lock

ライブラリ管理のための Gemfileやコントローラーやテストのための spec ファイルなどが出力されています。Railsでおなじみのファイルですね。

馴染みがない dynamodb.ymlyarn.lockも出力されています。(最近追えてないので最新の Rails では yarn が使われているのかもしれませんが)。

CRUDの雛形を作成

みんな大好き Scaffold です。Rails ライクに雛形を作成することができます

$ jets generate scaffold post title:string                                                                                                                                 
      invoke  active_record
      create    db/migrate/20200125133928_create_posts.rb
      create    app/models/post.rb
      invoke  resource_route
       route    resources :posts
      invoke  scaffold_controller
      create    app/controllers/posts_controller.rb
      invoke    erb
      create      app/views/posts
      create      app/views/posts/index.html.erb
      create      app/views/posts/edit.html.erb
      create      app/views/posts/show.html.erb
      create      app/views/posts/new.html.erb
      create      app/views/posts/_form.html.erb
      invoke    helper
      create      app/helpers/posts_helper.rb

データベースのスキーマ管理をするマイグレーションファイルやモデルとコントローラー、erbのテンプレート等が生成されています

データベースの接続先を変更する場合は .env.develoment.env.testを編集します。

以下は127.0.0.1(localhost)の13306ポートでLISTENしているMySQLに接続するサンプルです

.env.develoment

# Example .env.development, meant to be updated.
ENV_DEVELOPMENT_KEY=example1
# DATABASE_URL=mysql2://dbuser:dbpass@dbhost/demo_development?pool=5

# ↓↓追記部分
DATABASE_URL=mysql2://root@127.0.0.1:13306/demo_development?pool=5

.env.test

# Example .env.test, meant to be updated.
env_key1=env_value1
env_key2=env_value2

# ↓↓追記部分
DATABASE_URL=mysql2://root@127.0.0.1:13306/demo_test?pool=5

マイグレーションを実行

以下のコマンドでデータベースを作成し、マイグレーションファイルを実行し、データベースの準備を行います

$ jets db:create db:migrate

サーバーを起動

$ jets server                                                                                                                                                            => bundle exec rackup --port 8888 --host 127.0.0.1
Jets booting up in development mode!
Puma starting in single mode...
* Version 4.3.1 (ruby 2.6.5-p114), codename: Mysterious Traveller
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://127.0.0.1:8888
Use Ctrl-C to stop

出力された内容からサーバーがRackで起動されされ127.0.0.1(localhost)の 8888 をLISTENしてることがわかります

ブラウザで開いてみます

$ open http://localhost:8888/posts

シンプルな画面が表示されました 「New Post」 リンクをたどり新規登録をしてみます

登録できることを確認できました

AWS 環境にデプロイ

AWS環境にデプロイしていきます

RDSを使うので VPC Lamdbda を使った環境にデプロイしていきたいと思います

事前に以下のAWSリソースが作成されている想定です

  • VPC
  • RDS
  • サブネット

※ Lambdaが属するサブネットからNatGatewyへのルートが設定されていないと Lambda がタイムアウトしてしまう点にご注意ください

※ サンプルのCloudFormationテンプレートをご参照ください https://gist.github.com/cm-nishida-masayuki/800c8f6355de4f5c3128ad59834b9bf0

AWS環境でのDBへの接続情報を設定

AWS環境にデプロイした際に接続するRDSへの接続状況の設定を行います

.env.development.remote

ENV_DEVELOPMENT_KEY=example1
DATABASE_URL=mysql2://user:password@yourrdsendpoint/demo_development?pool=5

SubnetとSecurity Groupの設定します

config/environments/development.rb

Jets.application.configure do
  # Example:
  # config.function.memory_size = 1536

  # config.action_mailer.raise_delivery_errors = false
  # Docs: http://rubyonjets.com/docs/email-sending/

  config.function.vpc_config = {
    security_group_ids: %w[sg-xxx],
    subnet_ids: %w[subnet-xxx]
  }
end

マイグレーションを Lambda 上で実行するためのjobを追加します

jobs/command_job

class CommandJob < ApplicationJob
  def execute
    command = event['command'] || 'uptime'
    sh command
  end

  def create
    sh "jets db:create"
  end

  def migrate
    sh "jets db:migrate"
  end

  private
  def sh(command)
    puts "=> #{command}"
    puts `#{command}`
  end
end

デプロイします

$ jets deploy

~~~~ 省略
Stack success status: UPDATE_COMPLETE
Time took for stack deployment: 2m 25s.
Prewarming application.
API Gateway Endpoint: https://yourendpoint.execute-api.ap-northeast-1.amazonaws.com/dev/

このコマンドで以下を作成する CloudFormation テンプレートが作成され実行されます

  • API Gateway
  • Lambda

アップロードされた Lambda の中に ${アプリケーション名}-${環境}-command_job-create${アプリケーション名}-${環境}-command_job-migrateがあるので create => migrateの順でマネジメントコンソール上で実行します

deployコマンド実行時に出力されるURLに postsをつけてブラウザからアクセスすれば動作を確認できます

最後に

いかかでしたでしょうか?筆者もしばらく Ruby を触れておらず、まだ機能不足なところもありますが、Serverless アプリケーションを Rails ライクでお手軽に作れるので、機会があれば積極的に使っていきたいと思います。この記事が誰かの参考になれば幸いです

参考

tongueroo/jets-command-project: Shows how to run any command on AWS Lambda