dely Tech Blog

クラシル・TRILLを運営するdely株式会社の開発ブログです

コンテナサポートされたLambdaで湯婆婆実装してみた

f:id:bababachi:20201210180932p:plain

こんにちは!初めまして!delySREの中鉢です。 今年の10月にjoinしたばかりで、今は主にクラシルのインフラ基盤拡充を行っています。

本記事はdely #1 Advent Calendarの12日目の記事です。熱量が伝わる素晴らしい記事ばかりで戦々恐々ですが、がんばって書いていこうと思います。
昨日はサーバサイドエンジニアのYuji Takahashiさんの"DynamoDBでサポートされたPartiQLをRubySDKで利用する"でした。

tech.dely.jp

PartiQLでSQLライクにいじれるようになって、より手軽にDynamoのデータを取れるようになりましたね。アナウンスされたばかりの機能なので、今後も注目です!

delyの他の記事は以下リンクから!是非見て行って下さい。 adventar.org adventar.org

さて、kurashiruのバックボーンではAWSを利用しているのですが、AWSでは現在一年で最大のカンファレンス re:Invent が絶賛開催中です。

aws.amazon.com

今年はオンライン開催、しかも無料ということでどなたでも参加できますので是非チェックしてみてください。なんと1月まで続きます!

毎年ワクワクさせられるこの"お祭り"ですが、今年もたくさんのリリースやアナウンスが行われていますね! その中でLambdaのコンテナイメージランタイムサポートがアナウンスされました。

aws.amazon.com

ECRにアップロードしたコンテナイメージをそのままランタイムとして指定でき、その最大サイズはなんと10GB!
従来のzipパッケージのアップロードが最大250MBだったことを考えると、より使いやすく、できることも格段に増えた注目のアップデートだと思います!

今回はこれを使って、最近流行の湯婆婆ネタでFaaU(Function as a 湯婆婆)を実装します。語感が良いのでYじゃなくてUにしました。
記事書き終わってから気付きました

映画:千と千尋の神隠しのネタバレを含みますのでご注意を。

準備

今回作るのはAWSで、Lambda, ECR, API Gatewayを利用します。dockerはローカルで使えるようにしておいてください。
コンソールからawsコマンドが叩けて、credential設定ができていれば基本的に大丈夫です。

実装

それではいざ、尋常に。

コード

今回のファイル構成はこんな感じです

$ tree
.
├── Dockerfile
└── app.rb

シンプルイズベスト。 keep it simple. それぞれのファイルを見ていきます

  • app.rb
module LambdaFunction
  class Handler
    def self.yubaba(event:, context:)
      name = event['name']
      na_index = rand(name.size)
      na = name[na_index]
      message = "フン。#{name}というのかい。贅沢な名だねぇ。\n今からお前の名前は#{na}だ。いいかい、#{na}だよ。分かったら返事をするんだ、#{na}!!"
      return { statusCode: 200, body: message.to_json }
    end
  end
end
  • Dockerfile
FROM public.ecr.aws/lambda/ruby:2.7

COPY app.rb ./
CMD [ "app.LambdaFunction::Handler.yubaba" ]

受け取ったnameの値からランダムに1文字摘出してメッセージを返すだけ。

ベースイメージはECR Public gallery(こちらも今回発表されました! 詳細はこちら)から、現在提供されているAWS公式イメージ ruby2.7を利用します。

なお、自分でビルドしたコンテナイメージを使うことも可能ですが、RIC(AWS Lambda Runtime Interface Clients)を適用しLambdaのランタイムAPIと連携する必要があります。 公式イメージはRICが適用済みです。

テスト

今回のアナウンスでもう一つ気になっていたのが"RIE(Lambda Runtime Interface Emulator)"。

また、Lambda Runtime Interface Emulator をオープンソースとしてリリースします。これにより、コンテナイメージのローカルテストを実行して、Lambda にデプロイした際に実行されることを確認することができます。Lambda Runtime Interface Emulator は、AWS が提供するすべてのベースイメージに含まれており、任意のイメージでも使用できます。

つまりはwebサーバとして機能し、ローカルでテストができるようです。
ECR public garrayのイメージUsageにサンプルがあったのでやってみます

まずはイメージのbuild

$ docker build -t yubaba .             
[+] Building 1.5s (7/7) FINISHED                                                                                                          
 => [internal] load .dockerignore                                                                                                    0.0s
 => => transferring context: 2B                                                                                                      0.0s
 => [internal] load build definition from Dockerfile                                                                                 0.0s
 => => transferring dockerfile: 36B                                                                                                  0.0s
 => [internal] load metadata for public.ecr.aws/lambda/ruby:2.7                                                                      1.5s
 => [internal] load build context                                                                                                    0.0s
 => => transferring context: 481B                                                                                                    0.0s
 => CACHED [1/2] FROM public.ecr.aws/lambda/ruby:2.7@sha256:cb8c6f95a9464b07c8320985b292f4d95d14641c710f556146de6e9cc33ccc04         0.0s
 => [2/2] COPY app.rb ./                                                                                                             0.0s
 => exporting to image                                                                                                               0.0s
 => => exporting layers                                                                                                              0.0s
 => => writing image sha256:740ba6c06851e1e917f1590819ae61e56c88161da5ea6377790df36476a81116                                         0.0s
 => => naming to docker.io/library/yubaba  

そしてrun

$ docker run -p 9000:8080 yubaba:latest
time="2020-12-09T11:14:20.716" level=info msg="exec '/var/runtime/bootstrap' (cwd=/var/task, handler=)"

curlしてみます。参照するパスをRIEが提供してくれているようです。

$ curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -H "Content-Type: application/json" -d '{"name":"BETHESUN"}'
{"statusCode":200,"body":"\"フン。BETHESUNというのかい。贅沢な名だねぇ。\\n今からお前の名前はBだ。いいかい、Bだよ。分かったら返事をするんだ、B!!\""}%

めっちゃ簡単 これだけ手軽にテストできるのは良いですね。

なお、"BE THE SUN"はdelyのビジョンになります。下記コーポレートサイトにその想いが書かれていますので、合わせて見ていただけると嬉しいです。

ECRへpush

Lambdaからコンテナを利用するにはECRにイメージをpushしておく必要があります。

リポジトリから作成していきます。リポジトリ名はfaauで。

$ REPOSITORY_NAME=faau
$ aws ecr create-repository --repository-name ${REPOSITORY_NAME} --region=ap-northeast-1

{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-1:xxxxxxxx:repository/faau",
        "registryId": "xxxxxxxx",
        "repositoryName": "faau",
        "repositoryUri": "xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/faau",
        "createdAt": "2020-12-10T12:52:10+09:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": false
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
    

docker login

$ ACCOUNT_ID=xxxxxxxx
$ aws ecr get-login-password |  docker login --username AWS --password-stdin https://${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
Login Succeeded

イメージのビルド

$ docker build -t ${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${REPOSITORY_NAME}:v1.0 .
[+] Building 1.3s (7/7) FINISHED
 => [internal] load .dockerignore                                                                   0.0s
 => => transferring context: 2B                                                                     0.0s
 => [internal] load build definition from Dockerfile                                                0.0s
 => => transferring dockerfile: 36B                                                                 0.0s
 => [internal] load metadata for public.ecr.aws/lambda/ruby:2.7                                     1.2s
 => [internal] load build context                                                                   0.0s
 => => transferring context: 28B                                                                    0.0s
 => [1/2] FROM public.ecr.aws/lambda/ruby:2.7@sha256:38efb961e9fab0de46a5086b03b8217e5cd955fcbf917  0.0s
 => CACHED [2/2] COPY app.rb ./                                                                     0.0s
 => exporting to image                                                                              0.0s
 => => exporting layers                                                                             0.0s
 => => writing image sha256:0fbaa46b2e8efb3fad4ec0fa77324743cd9d0eb78b90ef9bd0fb82dee22d64ef        0.0s
 => => naming to 266255920091.dkr.ecr.ap-northeast-1.amazonaws.com/faau:v1.0                        0.0s

そして、push

$ docker push ${ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${REPOSITORY_NAME}:v1.0

The push refers to repository [xxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/faau]
ff87162bdcf5: Pushed
40bab667bbe5: Pushed
a76348bfadb0: Pushed
d6fa53d6caa6: Pushed
0360f591b796: Pushed
6b4100115ba9: Pushed
af6d16f2417e: Pushed
v1.0: digest: sha256:xxxxxxxxxxxx size: 1788

確認してみます!
マネジメントコンソールにログインし、サービスからECRを検索

f:id:bababachi:20201210174155p:plain リポジトリができています

f:id:bababachi:20201210174408p:plain イメージも無事確認できました!

Lambda関数の作成

それでは実際にLambdaから利用してみましょう。

f:id:bababachi:20201210174748p:plain
画像を参照 -> (コンテナ)イメージを参照 ですね

すんなり作成できました。早速テスト実行してみます。

テストケース
f:id:bababachi:20201210174910p:plain

実行
f:id:bababachi:20201210175120p:plain 問題ないですね!

APIGatewayと接続

せっかくなのでAPI化します。

API Gatewayから、RESTを選択。
名前を入力して作成。 f:id:bababachi:20201210175248p:plain

POSTメソッドを作成し、Lambda関数を選択。 f:id:bababachi:20201210175440p:plain

テストして f:id:bababachi:20201210175643p:plain

デプロイします。 f:id:bababachi:20201210175857p:plain ステージはcontract(契約書)で。申し訳程度に説明にセリフを入れておきます。

これで完了!

動作確認(※今は止めてます)

では、ローカルからcurlしてみます。

$ curl -X POST "https://atb4o0qjf3.execute-api.ap-northeast-1.amazonaws.com/contract" -H "Content-Type: application/json" -d '{"name":"びーざさん"}'
{"statusCode":200,"body":"\"フン。びーざさんというのかい。贅沢な名だねぇ。\\n今からお前の名前はんだ。いいかい、んだよ。分かったら返事をするんだ、ん!!\""}%

ん。。。
最後とか、湯婆婆って言うよりトトロのカンタになっちゃってますね。。。

無事、APIの実装まで完了しました!今回の検証はここまでになります!
本当に手軽にできました!

所感

今回はすごく簡易なアプリケーションとはいえ、とてもスムーズに実装することができました。
従来であれば、gemやnpmなど依存パッケージはローカルインストールして、固めてs3にアップして、、と手間かかっていましたが、検証した環境をそのまま上げることができるので、余計なことを考える必要がなくて良いですね!

イメージサイズが10GBまで許可されている点も大きな魅力ですね。ジョブ系アプリケーションの実行場所としては有力な選択肢になるのではないでしょうか。

もちろん、外部リソースへの接続は権限を別で用意する必要があったり、ひとつのコンテナだけなので載せる物によっては全部入り設計になったりしますが、そのような多くの場合そもそもLambdaという技術選定が違うんじゃないかとも思います。

AWSは他にも様々なコンテナプラットフォームがありますし、このような大きなアップデートがあったタイミングで見直すのもいいかもと思いました。

選択肢が増え続ける中で、用途に合ったソリューションを適切に選定していくためにもどんどん触って使い心地を確かめていきたいと思います!

おわりに

明日はNakazawaさんの「Carthageで生成したframeworkの管理でRomeを導入してみた」です!楽しみにしています!

さいごに、delyではエンジニアを絶賛大募集です! BE THE SUNをビジョンに掲げ、プロダクトに情熱を注いでみませんか?

採用ページはこちら! join-us.dely.jp

こちらはコーポレートサイトです。 www.dely.jp

また、「クラシル Tech Talk」などのイベントも多数行っています。 エントリー前に開発部の様子を知りたいという方はぜひ覗いてみてください。ご応募をお待ちしております!

bethesun.connpass.com

それでは!