これは
初老丸アドベントカレンダー 2018 の 8 日目の記事になる予定です.
https://qiita.com/advent-calendar/2018/syoroumaru
加藤さん, 事件です.
ずっと待たれていたはず, もはや諦めかけていたかもしれない AWS Lambda のランタイムに Ruby が追加されたとの一報が我々の元に入りました.
https://aws.amazon.com/jp/blogs/compute/announcing-ruby-support-for-aws-lambda/
おお〜. なんちゃって 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〜〜.