これは
初老丸アドベントカレンダー 2018 の 8 日目の記事になる予定です.
加藤さん, 事件です.
ずっと待たれていたはず, もはや諦めかけていたかもしれない AWS Lambda のランタイムに Ruby が追加されたとの一報が我々の元に入りました.
おお〜. なんちゃって Rubist の私もこれまで作ってきた Ruby スクリプトを Lambda で実行出来るかもしれないという興奮が今も続いております.
ということで
早速, 上記の URL に掲載されているサンプルを参考に簡単な Ruby スクリプトを Lambda 上で動かしてみたいと思います.
検証環境
以下のような環境で動作確認を取ります.
$ ruby --version
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-darwin17]
$ python --version
Python 3.7.0
$ sam --version
SAM CLI, version 0.8.0
$ aws --version
aws-cli/1.16.66 Python/3.7.0 Darwin/17.7.0 botocore/1.12.56
初めて sam を使ってみましたが, とても簡単に Lambda ファンクションのデプロイまで出来ました. Serverless framework と比較すると機能不足は否めませんが, AWS 純正なので新サービスへの対応も早かったりするのかなということで, もう少し使い込んでみようと思います.
まずは, サンプルイベントを生成する
とりあえず, ローカルで Ruby で書いた関数を動かしてみたいので, Lambda をローカルで実行する際に利用するサンプルイベントを生成します.
$ sam local generate-event s3 put --bucket=foo --key=bar > event_file.json
これを実行すると, 以下のような JSON イベントが生成されます.
$ cat event_file.json
{
"Records": [
{
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "us-east-1",
"eventTime": "1970-01-01T00:00:00.000Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "EXAMPLE"
},
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
},
"responseElements": {
"x-amz-request-id": "EXAMPLE123456789",
"x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "testConfigRule",
"bucket": {
"name": "foo",
"ownerIdentity": {
"principalId": "EXAMPLE"
},
"arn": "arn:aws:s3:::foo"
},
"object": {
"key": "bar",
"size": 1024,
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901"
}
}
}
]
}
今回は, この JSON イベントから S3 のオブジェクトキーを抜き出す関数を Ruby で書いてみます.
祝・Ruby で書く Lambda ファンクション
す, すいません. とりあえず, 雑に書きました.
def hello(event:, context:)
key = event["Records"][0]["s3"]["object"]["key"]
key
end
なんのひねりも, エラー処理もない, 自分の Ruby スキルのレベルが伺えるスクリプトです.
sam に必要な template.yaml
template.yaml (.yml ではない) を以下のように書きました.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: 'serverless ruby sample.'
Resources:
ServerlessRubySample:
Type: AWS::Serverless::Function
Properties:
Handler: sample.hello
Runtime: ruby2.5
Outputs:
ServerlessRubySample:
Description: Serverless Ruby Sample Lambda Function ARN
Value:
Fn::GetAtt:
- ServerlessRubySample
- Arn
なんとなく CloudFormation のテンプレートっぽい佇まいです. Runtime
の ruby2.5
が眩しいです.
まずはローカルでテスト
sam にもローカルで Lambda ファンクションを実行出来る local invoke
というサブコマンドが用意されていますので, これを利用することで簡単にローカルで実行することが可能です.
$ sam local invoke ServerlessRubySample -e event_file.json
2018-11-30 08:33:13 Found credentials in shared credentials file: ~/.aws/credentials
2018-11-30 08:33:14 Invoking sample.hello (ruby2.5)
Fetching lambci/lambda:ruby2.5 Docker container image......
2018-11-30 08:33:17 Mounting /path/to/serverless-ruby-sample as /var/task:ro inside runtime container
START RequestId: 52fdfc07-2182-154f-163f-5f0f9a621d72 Version: $LATEST
END RequestId: 52fdfc07-2182-154f-163f-5f0f9a621d72
REPORT RequestId: 52fdfc07-2182-154f-163f-5f0f9a621d72 Duration: 5.64 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 18 MB
"bar"
"bar"
が出力されることを確認出来ます. あっという間にローカル環境で Ruby で書いた Lambda ファンクションが動いてしまいました.
あとはデプロイ
引き続き, デプロイです. sam では CloudFormation のテンプレートを書き出して, そのテンプレートを使って Create Stack するような感じでデプロイするようです. もしかしたら, Serverless Framework も同じような挙動なのかもしれません. 以下のように 2 ステップでデプロイしました.
# packaged-template.yaml を生成
sam package --template-file template.yaml \
--output-template-file packaged-template.yaml \
--s3-bucket oreno-sam-bucket
# packaged-template.yaml を利用してデプロイ
sam deploy --template-file packaged-template.yaml \
--stack-name ServerlessRubySample \
--capabilities CAPABILITY_IAM
以下のように出力されました.
# packaged-template.yaml を生成
$ sam package --template-file template.yaml \
> --output-template-file packaged-template.yaml \
> --s3-bucket oreno-sam-bucket
Uploading to b55e36e493168dc4d6627ee148c1ac97 1275 / 1275.0 (100.00%)
Successfully packaged artifacts and wrote output template to file packaged-template.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /Users/kawahara/sandboxies/sam/serverless-ruby-sample/packaged-template.yaml --stack-name <YOUR STACK NAME>
# packaged-template.yaml を使って Create Stack しているのかな...
$ sam deploy --template-file packaged-template.yaml \
> --stack-name ServerlessRubySample \
--capabilities CAPABILITY_IAM> --capabilities CAPABILITY_IAM
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - ServerlessRubySample
動作確認
動作確認も Ruby で書きましょう. 以下のように aws-sdk-lambda を使ったコードです. 事前に aws-sdk-lambda をインストールしておきましょう.
require 'aws-sdk-lambda'
require 'json'
client = Aws::Lambda::Client.new(region: 'ap-northeast-1')
payload =<<"EOS"
{
"Records": [
{
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "testConfigRule",
"bucket": {
"name": "foo",
"ownerIdentity": {
"principalId": "EXAMPLE"
},
"arn": "arn:aws:s3:::foo"
},
"object": {
"key": "bar",
"size": 1024,
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901"
}
}
}
]
}
EOS
resp = client.invoke({
function_name: 'ServerlessRubySample-ServerlessRubySample-xxxxxxxxxxx',
invocation_type: 'RequestResponse',
log_type: 'None',
payload: payload
})
res = JSON.parse(resp.payload.string)
puts res
function_name
だけは, マネジメントコンソールで確認しましょう. このスクリプトを適当に invoke.rb とか名前をつけて保存しておきます.
$ bundle exec ruby invoke.rb
以下のように出力されました.
$ bundle exe ruby invoke.rb
bar
おお〜, いい感じです. CloudWatch Logs にもログが記録されていることを確認しています.
以上
Ruby で Lambda ファンクションが書けるなんて, 今年の頭に誰が予想していたでしょうか (結構, 予想していたりしたらすいません). 本当に嬉しい限りです.
レッツ Ruby on Lambda〜〜.