AWS Lambda RubyでNative Extensionsを使用するgemを使うには?serverlessも使ってみた!

f:id:hirokishirai:20181205123107p:plain

初めまして、Railsエンジニアの白井です。 最近彼女が出来て会社の人に幸せ(惚気)を振りまく活動をしています!

さて、先日AWS re:Invent 2018にてAWS LambdaがRubyランタイム対応の発表がなされました!(リリース

そしてserverlessもすぐにRubyに対応

弊社は私含めRubyエンジニアが多数いるため、とてもとても嬉しいアナウンスメントでした。

早速使ってみるとNative Extensionsを使用するgemを使いたい時にちょっと詰まったのでシェアします!

この記事を読んだらわかること

この記事では、 AWS Lambda RubyランタイムでNative Extensionsを使用するgemを使ったLambda関数を作る手順をまとめています。

※Native Extensionsを使用しないgemのみを使ったLambda関数は未検証です。
※serverelessを使用して簡易的に行なっていますが、使用しない場合は置き換えて読んでください。

Native Extensionsを使用するgemをLambdaで使うには

Native Extensionsを用いたgemを使いたい場合はLambda 実行環境同等の環境 でbundle install、デプロイしてあげる必要があります。

幸いにもLambdaのベースとなるAMI(ログインが必要です)が公開されているのでここにRubyとserverlessの環境を作り、デプロイしてみましょう。

Lambdaが動作している環境と同じ環境を作る

AMI - amzn-ami-hvm-2017.03.1.20170812-x86_64-gp2(ログインが必要です)にアクセスするとLambdaのベースとなるAMIがあります。 「作成」 から指示に従ってEC2インスタンスを作成します。インスタンスタイプはt2.microの無料枠で済ませてしまいましょう!

f:id:hirokishirai:20181205110639p:plain

インスタンスが立ち上がったらsshしてRubyとServerlessをインストールします。

# ※この記事ではセットアップの詳細の説明は省かせていただきます。

# 必要なパッケージのインストール
sudo yum -y install gcc-c++ glibc-headers openssl-devel readline libyaml-devel readline-devel zlib zlib-devel libffi-devel libxml2 libxslt libxml2-devel libxslt-devel sqlite-devel git nodejs make

# rbenvのインストール
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
git clone git://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
sudo ~/.rbenv/plugins/ruby-build/install.sh

# rubyのインストール
rbenv install 2.5.3
rbenv global 2.5.3

# bundlerのインストール
gem install bundler

# nodejs, npm, serverlessのインストール
curl --silent --location https://rpm.nodesource.com/setup_6.x | sudo bash -
sudo npm install -g serverless

echo 'export AWS_ACCESS_KEY_ID={YOUR_AWS_ACCESS_KEY_ID}' >> ~/.bash_profile
echo 'export AWS_SECRET_ACCESS_KEY={YOUR_AWS_SECRET_ACCESS_KEY}' >> ~/.bash_profile
source ~/.bash_profile

これで準備が整いました!

実際に簡単なRuby Lambda関数を作ってみる

作るもの

お世話になっている方も多いであろうgem fakerを使わせていただき、実行するたびにFakeな名前を生成してくれる関数を作ってみます。

serverlessのテンプレートからプロジェクトを開始

serverless create --template aws-ruby --path faker
cd faker
bundle init

すると

.
├── Gemfile
├── handler.rb
└── serverless.yml

が生成されますね。

早速fakerを追加してbundle installしましょう。

# Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

gem 'faker', :github => 'stympy/faker', :branch => 'master'
# Gemfile.lockの更新
bundle install
# Gemfile.lockを読み込んで vendor/bundle に依存gemをインストール
bundle install --deployment

次は関数ですね。

# handler.rb
require 'rubygems'
require 'bundler'
Bundler.require

def hello(event:, context:)
  prefix = event['prefix']
  { statusCode: 200, body: JSON.generate(prefix + Faker::Name.name) }
end

非常にシンプル!笑

デプロイ・実行

ではデプロイして実行してみましょう。

serverless deploy

次にデプロイしたlambda関数を実際に実行してみましょう。

# input_event.json
{
  "prefix": "Mr."
}
serverless invoke -f hello -p input_event.json
# => {
#       "statusCode": 200,
#       "body": "Mr.Ginger Lockman"
#    }

できた!

ジンジャーロックマンってだれ。

裏話

実はもともと複数のRubyプロジェクトで使う予定で不動産投資シミュレーションの社内プライベートgemを開発していたのですが、途中で他言語でも使いたいニーズが出てきて、traveling-rubyで無理くりrubyを動かしてAPI化したその次の日にLambda Rubyサポート発表があってびっくり!

traveling-rubyはRuby 2.2.2までしか対応していないのでわざわざgemを古い記法に書き直したりもしていたのですが、そんな苦労があと1日待てば必要なかったという笑

とはいえ、とても素晴らしい発表でした! Rubyエンジニアが多い弊社でもLambdaを扱える人が増えてありがたい限り!

また新しい発見があったらブログ書きますね!