Образ контейнера AWS Lambda для кода Ruby — как провести локальное тестирование с помощью docker run

Я переношу Ruby 2.7 Lambda из развертывания zip-файла в развертывание образа контейнера.

Когда я развертываю свой контейнер в AWS Lambda, контейнер ведет себя так, как я надеюсь.

Когда я пытаюсь протестировать то же изображение локально с помощью docker run {my-image-name}, я сталкиваюсь с двумя проблемами.

  1. Параметры недоступны из объекта события таким же образом
  2. Заголовки возврата и код состояния не учитываются так же, как они обрабатываются из Lambda.

Мои вопросы

  • Нужно ли мне включать что-то еще в мой файл докеров, чтобы помочь с лямбда-моделированием?
  • Нужно ли использовать другую точку входа в моем файле докеров?
  • Я нашел документацию для «Эмулятора интерфейса времени выполнения AWS Lambda», но мне неясно, предназначен ли он для решения проблем, с которыми я сталкиваюсь.

Вот упрощенная версия того, что я пытаюсь проверить.

Докерфайл

FROM public.ecr.aws/lambda/ruby:2.7

COPY * ./

RUN bundle install 

CMD [ "lambda_function.LambdaFunctions::Handler.process" ]

Gemfile

source "https://rubygems.org"

Lambda_function.rb



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

Работа с AWS Lambda

У нас есть балансировщик нагрузки, делающий эту 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}

POST-запрос к локальному докеру

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\"}}"
}

GET-запрос к локальному докеру

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

Эта проблема выглядит связанной: github.com/aws/aws-lambda-runtime-interface-emulator/issues/‌​8

terrywb 19.12.2020 00:46

Похоже, вы сравниваете лямбда-функцию, вызываемую через API Gateway/Load Balancer на AWS, с локальным эмулятором интерфейса среды выполнения. Последний, выставляя локальный сервер, не имеет каких-либо функций первых, все, что он делает, это передает содержимое тела POST-запроса в качестве event параметра функции.

Andre.IDK 21.12.2020 15:08
Почему в Python есть оператор &quot;pass&quot;?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
2
1 115
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Создайте приложение Sinatra для имитации действий Application Load Balancer.

Основываясь на следующем документе, я считаю, что мне нужно смоделировать действия, выполняемые балансировщиком нагрузки приложений AWS, который находится перед моим лямбда-кодом. См. https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html

Имитация-лямбда-alb/alb_simulate.rb

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

Имитация-лямбда-альб/Dockerfile

FROM ruby:2.7

RUN gem install bundler

COPY Gemfile Gemfile

RUN bundle install

COPY . .

EXPOSE 8091

CMD ["ruby", "alb_simulate.rb"]

Докер-compose.yml

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

Запустите Sinatra для имитации Application Load Balancer

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":[""]}}}

Другие вопросы по теме