ä½çªç ããåãããªããã©ãæè¿ãã£ãã®ã§ã
åæç¥è
- AWS Lambda + Amazon API Gateway 㧠HTTP ãªã¯ã¨ã¹ããåãä»ãããã¨ãã§ãã
- AWS Lambda ã§ã¯ã³ã³ããã¤ã¡ã¼ã¸ãåããã
- AWS Lambda 㧠Sinatra ã¢ããªãåããããã®å ¬å¼ãµã³ãã«ããã
ã¤ã¾ãã³ã³ããåãã Sinatra ã¢ããªã Lambda ä¸ã«ãããã¤ã㦠HTTP ãªã¯ã¨ã¹ããåãä»ãããã¨ãã§ããã
åããæºåã¯ããå ¨é¨æ´ã£ã¦ãã¦ããæ軽ããã§ããã
Ruby ã¢ããªã Lambda ã§åããã³ã³ããã¤ã¡ã¼ã¸ãä½ã
Sinatra 以åã«ããããã Ruby ã¯ã©ããã£ã¦ Lambda Container Image ä¸ã§åãã®ããå ¬å¼ã«ãã¥ã¼ããªã¢ã«ãããã®ã§ãã®éãã§è¯ãã
Deploy Ruby Lambda functions with container images - AWS Lambda
https://gallery.ecr.aws/lambda/ruby ã® Usage ããªããã
- https://gallery.ecr.aws/lambda/ruby ãã base image ãé¸ãã§ãDockerfile ãä½ã£ã¦
- docker build ãã¦
- docker run 㧠Image ãç«ã¡ä¸ãã㨠HTTP ã§å¾ ã¡åããã®ã§
- curl ã§çºç«ããã
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'
è¬ URL ã ãã©ããããããã®ãã¨ãã¦è¦ãã¦ããã°è¯ãã
ç¹çãã¹ãç¹
ENV["GEM_PATH"] #=> "/var/task/vendor/bundle/ruby/2.7.0:/opt/ruby/gems/2.7.0"
ãªã®ã§ãããã« gem ãå ¥ãã¦ãã㨠bundle exec ããªãã¦ã gem ã使ãããããã¾ã bundler 使ãã°è¯ãã¨æãã¾ãããã
Rack ã¢ããªã Lambda ã§åãã
åè¿°ããå ¬å¼ã® https://github.com/aws-samples/serverless-sinatra-sample ã®ä»ã«ã https://github.com/logandk/serverless-rack ã¨ãããã®ãããã
ä»çµã¿
ã©ã¡ããè㯠Rack::Builder.parse_file
ã§ãã config.ru
ã eval ãããã¨ã§å®è¡ããã Rack App ãåãåºãå¦çã
- https://github.com/aws-samples/serverless-sinatra-sample/blob/807901d90c4ad0b9d1f55b8a44c9217eb709d161/lambda.rb#L22
- https://github.com/logandk/serverless-rack/blob/1.0.7/lib/rack_adapter.rb#L17
App ãåå¾ã§ããã®ã§ãenv
ãçµã¿ç«ã¦ã¦
- https://github.com/aws-samples/serverless-sinatra-sample/blob/807901d90c4ad0b9d1f55b8a44c9217eb709d161/lambda.rb#L38-L50
- https://github.com/logandk/serverless-rack/blob/1.0.7/lib/serverless_rack.rb#L85-L109
app.call(env)
ãã¦
- https://github.com/aws-samples/serverless-sinatra-sample/blob/807901d90c4ad0b9d1f55b8a44c9217eb709d161/lambda.rb#L68
- https://github.com/logandk/serverless-rack/blob/1.0.7/lib/serverless_rack.rb#L226-L233
Rack ã® status, headers, body
ã®çµãããLambda ã® response ã«ãªãããã« JSON ãçµã¿ç«ã¦ç´ã
- https://github.com/aws-samples/serverless-sinatra-sample/blob/807901d90c4ad0b9d1f55b8a44c9217eb709d161/lambda.rb#L78-L82
- https://github.com/logandk/serverless-rack/blob/1.0.7/lib/serverless_rack.rb#L235-L241
Lambda ã® response ã¨ããã®ã¯ã³ã¬ãhttps://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
{ "isBase64Encoded": true|false, "statusCode": httpStatusCode, "headers": { "headerName": "headerValue", ... }, "multiValueHeaders": { "headerName": ["headerValue", "headerValue2", ...], ... }, "body": "..." }
å®è£
ãããèªåã® Rack ã¢ããªã«ã©ãçµã¿è¾¼ããã¨ããã¨
app/config.ru 㨠lambda.rb ãç½®ã㦠Dockerfile ã® CMD ã§ã¯ lambda.handler
ãæå®ããã¨è¯ãã
PROJECT_ROOT âââ app/ â âââ config.ru â âââ Gemfile â âââ Gemfile.lock âââ Dockerfile âââ lambda.rb
lambda.rb 㯠https://github.com/aws-samples/serverless-sinatra-sample/ ããã³ãã¼ãã¾ãã*1
ä»ã®ãã¡ã¤ã«ã¯ãããªæãã
# app/Gemfile source "https://rubygems.org" gem "rack"
# app/config.ru run ->(env) { ["200", { "Content-Type" => "text/plain" }, ["OK"]] }
FROM public.ecr.aws/lambda/ruby:2.7 COPY lambda.rb ${LAMBDA_TASK_ROOT} # rack ã ${LAMBDA_TASK_ROOT}/vendor/bundle ã«å ¥ããã WORKDIR ${LAMBDA_TASK_ROOT}/app COPY app/Gemfile app/Gemfile.lock . RUN bundle config set path ${LAMBDA_TASK_ROOT}/vendor/bundle RUN bundle install COPY app/config.ru . WORKDIR /var/task CMD [ "lambda.handler" ]
ã§ãå®è¡ããã¨ãã¯
curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"httpMethod":"GET","requestContext":{}}'
ããã¨ãLambda ã® JSON response ãåå¾ã§ããã
{"statusCode":"200","headers":{"Content-Type":"text/plain"},"body":"OK"}
渡ã JSON ã®ãã©ã¡ã¼ã¿ã¯ https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format ãåç §ã
{ "resource": "Resource path", "path": "Path parameter", "httpMethod": "Incoming request's method name" "headers": {String containing incoming request headers} "multiValueHeaders": {List of strings containing incoming request headers} "queryStringParameters": {query string parameters } "multiValueQueryStringParameters": {List of query string parameters} "pathParameters": {path parameters} "stageVariables": {Applicable stage variables} "requestContext": {Request context, including authorizer-returned key-value pairs} "body": "A JSON string of the request payload." "isBase64Encoded": "A boolean flag to indicate if the applicable request payload is Base64-encoded" }
rackup ãã HTTP Server ã¨ã㦠Docker Image ãå®è¡ããã
Lambda ã® Docker Image ã¨ãã¦å®è¡ããã¨ã㯠Lambda function for proxy integration ã®å½¢å¼ã§ JSON ãããã¨ãããªãã¨ãããªããã¨ããã®ã¯ä»ã¾ã§æ¸ãã¦ããéãã
éçºä¸ã¯ bundle exec rackup
ãã¦ããã°ãããã ãã©ãæ£ããç¼ãã¦ããä¸å®ãªã¨ããããã®ã§ãDocker Image ä¸ã® Rack ã¢ããªããã©ã¦ã¶ããå®è¡ãããã
ã¤ã¾ã
- HTTP ãµã¼ããç«ã£ã¦
- ãªã¯ã¨ã¹ãããããããã« JSON ã«å¤æã㦠Lambda ã«æãã¦
- Lambda ããã®ã¬ã¹ãã³ã¹ããããããã« HTTP ã«å¤æãã¦è¿ã
ãã¦ããã proxy (ã¤ã¾ã API Gateway ã ALB ç¸å½ã®ãã®) ãããã¨ä¾¿å©ã ãããã¨ããããã§éã«ãããªã®ãç¨æãã¾ããã
ã³ã³ãããç«ã¦ã¦ãä¸ã§ãã® proxy ãç«ã¦ã¦ããã¨ãhttp://localhost/ ã§ã³ã³ããã®ä¸ã® Lambda ã®ä¸ã® Rack ã¢ããªã¨ããã¨ãã§ããã
絶対ã©ããã«ãã£ã¨è¯ããã¤ããã¨æãã®ã§å
¨ç¶ä½ãè¾¼ãã§ãªãã(ä¾ãã° multiValueHeaders
ã isBase64Encoded
ã¯å¯¾å¿ãã¦ããªã)
#!/usr/bin/env ruby require "json" require "net/http" require "webrick" LAMBDA_ENDPOINT = "http://localhost:9000/2015-03-31/functions/function/invocations" s = WEBrick::HTTPServer.new s.mount_proc("/") do |req, res| uri = URI(LAMBDA_ENDPOINT) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = uri.scheme === "https" headers = {} req.each do |k, v| headers[k] = v end json_data = { httpMethod: req.request_method, path: req.path, queryStringParameters: req.query, body: req.body, headers: headers, requestContext: {}, } lambda_res = http.post( uri.path, JSON.generate(json_data), { "Content-Type" => "application/json" }, ) lambda_inner_res = JSON.parse(lambda_res.body) res.status = lambda_inner_res["statusCode"] lambda_inner_res["headers"].each do |k, v| res[k] = v end res.body = lambda_inner_res["body"] end Signal.trap("INT") { s.shutdown } s.start
ã¾ã¨ã
- Lambda ã§ã³ã³ããã«å ¥ãã Sinatra ã¢ããªãåãããã¨ãã§ãã
- HTTP Request ã Rack ã«å¤æãã¦å®è¡ããä»çµã¿ã説æãã
- Lambda function for proxy integration ã®å½¢å¼ã§ JSON ãããã¨ããããã¨ã«ãªãã®ã§ãproxy ç«ã¦ãã¨ä¾¿å©
*1:å®éã¯ãã£ã¬ã¯ããªæ§é å¤ããã apigatewayv2 対å¿ãããã§ãã¯ãå¥ç©ã«ãªã£ã¦ãããã©èª¬æé¢åãªã®ã§çç¥