AWS Lambda 上で、任意の Web アプリケーションフレームワークを動かせる「Lambda Web Adapter」が、バージョン 0.8.1 で HTTP 以外のイベントも受けられるようになりました。
ここでは、Ruby製Webアプリケーションフレームワーク「Sinatra」を、AWS Lambda + Lambda Web Adapter で動かす最小構成を紹介します。
1. 動作確認用の最小構成Sinatraアプリケーション
いたって普通のSinatraアプリですね。これが AWS Lambda でそのまま動作します。
require 'sinatra'
get '/' do
logger.info params # QueryString
'Hello! I am <b>Sinatra</b>.'
end
post '/' do
logger.info params # QueryString and/or x-www-form-urlencoded
logger.info request.body.read # e.g.) application/json
'Post data recived.'
end
post '/events' do # for Non-HTTP Event Trigger
logger.info request.body.read # Logging body
'success' # w/ HTTP 200
end
mkdir -p sinatra_app1
cd sinatra_app1
bundle init
bundle add sinatra
bundle add rackup
bundle add puma
ls
#=> Gemfile Gemfile.lock app.rb
ls
#=> Gemfile Gemfile.lock app.rb
bundle exec ruby app.rb -p 8080
# CTRL+C で終了
# 別ターミナルから
curl localhost:8080/
#=> Hello! I am <b>Sinatra</b>.
Dockerfile 作成とビルド
先ほどの Sinatra アプリに Runtime である Ruby 本体を同梱してコンテナイメージを作成します。
FROM public.ecr.aws/docker/library/ruby:3.4
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.8.4 /lambda-adapter /opt/extensions/lambda-adapter
WORKDIR /var/task
COPY ./ ./
RUN bundle install
CMD ["bundle", "exec", "ruby", "app.rb", "-o", "0.0.0.0", "-p", "8080"]
ls
#=> Dockerfile Gemfile Gemfile.lock app.rb
docker build -t sinatra_app1 .
docker images sinatra_app1
#=> REPOSITORY TAG IMAGE ID CREATED SIZE
#=> sinatra_app1 latest 7d50536b75db 25 minutes ago 1.01GB
docker run -it --rm -p 8080:8080 sinatra_app1
# CTRL+C で終了
# 別ターミナルから
curl localhost:8080/
#=> Hello! I am <b>Sinatra</b>.
この後の作業
AWS Lambda で Amazon Elastic Container Registry(ECR) 上のコンテナを利用する方法と同じ手順です。
- Amazon ECR にレジストリを作成
- コンテナイメージに tag を付与
- Amazon ECR レジストリへコンテナイメージを push
${ACCOUNTID}
や ${REGION}
は読み替えてください。
aws ecr create-repository --repository-name sinatra_app1_lambda #1
docker tag sinatra_app1:latest ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/sinatra_app1_lambda:latest #2
aws ecr get-login-password | docker login --username AWS --password-stdin ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com #3a
docker push ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/sinatra_app1_lambda:latest #3b
aws --output text ecr list-images --repository-name sinatra_app1_lambda
#=> IMAGEIDS sha256:3bc6833093c4adaefddba0737501226fa02e9ac0e7ebe83c82b5111300f12639 latest
あとは、AWS Lambda の操作です。関数作成時に「コンテナイメージ」を参照するように設定します。関数のアーキテクチャは x86_64
、メモリーは 512MB
を割り当てましょう。
Lambda 関数の動作ログは CloudWatch Logs で確認できます。
トラブルシュート:
-
/usr/local/lib/ruby/3.3.0/rubygems.rb:165: [BUG] Segmentation fault at 0xffffffffffffffff
が発生したら:- メモリー不足です。Lambda 関数へのメモリー割り当てを増やしてください。
-
INIT_REPORT Init Duration: xx.xx ms Phase: init Status: error Error Type: Extension.LaunchError
が発生したら:- アーキテクチャーの不一致です。コンテナイメージ内のアーキテクチャーと、Lambda 関数のアーキテクチャーが一致しているか確認して、必要であれば Lambda 関数を再作成してください。
コンテナイメージの更新 = 関数の更新
docker build -t sinatra_app1 .
docker tag sinatra_app1:latest ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/sinatra_app1_lambda:latest
docker push ${ACCOUNTID}.dkr.ecr.${REGION}.amazonaws.com/sinatra_app1_lambda:latest
あとは AWS Lambda 関数側で「新しいイメージをデプロイ」から、更新後のコンテナイメージを選んでデプロイすれば、更新されます。
あとがき
Non-HTTP トリガーは ここを見ると、 /events
というパスへ Content-Type=application/json で HTTP POST される仕様ですね。Web アプリの要領で実装できます。
※ 個人的には lambda_handler()
でいい気もしてますが。
コード例が examples にもあります
これと同じ内容が https://github.com/awslabs/aws-lambda-web-adapter/tree/main/examples/sinatra にあります。若干のディレクトリ構成の違いはありますが同じものです。
参考
- コンテナ利用者に捧げる AWS Lambda の新しい開発方式 !
- AWS::Serverless::Function
- Amazon ECR Public Gallery > search > docker > library/ruby "How to use this image"
- awslabs/aws-lambda-web-adapter | GitHub
- AWS SAM で AWS Lambda の 関数 URL を利用してみました
- SAMを利用したLambda(Function URLs)デプロイ
[EoT]