Я переношу Ruby 2.7 Lambda из развертывания zip-файла в развертывание образа контейнера.
Когда я развертываю свой контейнер в AWS Lambda, контейнер ведет себя так, как я надеюсь.
Когда я пытаюсь протестировать то же изображение локально с помощью docker run {my-image-name}, я сталкиваюсь с двумя проблемами.
Вот упрощенная версия того, что я пытаюсь проверить.
FROM public.ecr.aws/lambda/ruby:2.7
COPY * ./
RUN bundle install
CMD [ "lambda_function.LambdaFunctions::Handler.process" ]
source "https://rubygems.org"
require 'json'
module LambdaFunctions
class Handler
def self.process(event:,context:)
begin
json = {
message: 'This is a placeholder for your lambda code',
event: event
}.to_json
{
headers: {
'Access-Control-Allow-Origin': '*'
},
statusCode: 200,
body: json
}
rescue => e
{
headers: {
'Access-Control-Allow-Origin': '*'
},
statusCode: 500,
body: { error: e.message }.to_json
}
end
end
end
end
У нас есть балансировщик нагрузки, делающий эту Lambda доступной
curl -v https://{my-load-balancer-url}/owners?path=owners
Ответ: обратите внимание, что балансировщик нагрузки преобразовал мой запрос GET в запрос POST.
{
"message": "This is a placeholder for your lambda code",
"event": {
"requestContext": {
"elb": {...}
},
"httpMethod": "POST",
"path": "/owners",
"queryStringParameters": {
"path": "owners"
},
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, deflate, br",
"cache-control": "no-cache",
"connection": "keep-alive",
"content-length": "0",
...
},
"body": "",
"isBase64Encoded": false
}
}
docker run --rm --name lsample -p 9000:8080 -d {my-image-name}
curl -v http://localhost:9000/2015-03-31/functions/function/invocations -d '{"path": "owners"}'
Обратите внимание, что заголовки возвращаются как часть ответа.
Заголовки ответа
< HTTP/1.1 200 OK
< Date: Fri, 18 Dec 2020 19:06:56 GMT
< Content-Length: 166
< Content-Type: text/plain; charset=utf-8
Тело ответа (отформатированное)
{
"headers": {
"Access-Control-Allow-Origin": "*"
},
"statusCode": 200,
"body": "{\"message\":\"This is a placeholder for your lambda code\",\"event\":{\"path\":\"owners\"}}"
}
curl -v http://localhost:9000/2015-03-31/functions/function/invocations?path=owners
Контент не возвращается
< HTTP/1.1 200 OK
< Date: Fri, 18 Dec 2020 19:10:08 GMT
< Content-Length: 0
Похоже, вы сравниваете лямбда-функцию, вызываемую через API Gateway/Load Balancer на AWS, с локальным эмулятором интерфейса среды выполнения. Последний, выставляя локальный сервер, не имеет каких-либо функций первых, все, что он делает, это передает содержимое тела POST-запроса в качестве event параметра функции.
Основываясь на следующем документе, я считаю, что мне нужно смоделировать действия, выполняемые балансировщиком нагрузки приложений AWS, который находится перед моим лямбда-кодом. См. https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
require 'sinatra/base'
require 'json'
require 'httpclient'
# ruby app.rb -o 0.0.0.0
set :port, 8091
set :bind, '0.0.0.0'
get '/web' do
send_file "../web/index.html"
end
get '/web/' do
send_file "../web/index.html"
end
get '/web/:filename' do |filename|
send_file "../web/#{filename}"
end
get '/lambda*' do
path = params['splat'][0]
path=path.gsub(/^lambda//,'')
event = {path: path, queryStringParameters: params}.to_json
cli = HTTPClient.new
url = "#{ENV['LAMBDA_DOCKER_HOST']}/2015-03-31/functions/function/invocations"
resp = cli.post(url, event)
body = JSON.parse(resp.body)
status body['statusCode']
headers body['headers']
body['body']
end
FROM ruby:2.7
RUN gem install bundler
COPY Gemfile Gemfile
RUN bundle install
COPY . .
EXPOSE 8091
CMD ["ruby", "alb_simulate.rb"]
version: '3.7'
networks:
mynet:
services:
lambda-container:
container_name: lambda-container
# your container image goes here, or you can test with the following
image: cdluc3/mysql-ruby-lambda
stdin_open: true
tty: true
ports:
- published: 8090
target: 8080
networks:
mynet:
alb-simulate:
container_name: alb-simulate
# this image contains the code in this answer
image: cdluc3/simulate-lambda-alb
networks:
mynet:
environment:
LAMBDA_DOCKER_HOST: http://lambda-container:8080
ports:
- published: 8091
target: 8091
depends_on:
- lambda-container
docker-compose up
curl "http://localhost:8091/lambda?path=test&foo=bar"
{"message":"This is a placeholder for your lambda code","event":{"path":"","queryStringParameters":{"path":"test","foo":"bar","splat":[""]}}}
Эта проблема выглядит связанной: github.com/aws/aws-lambda-runtime-interface-emulator/issues/8