【问题标题】:AWS Lambda Container Image for Ruby Code -- How to test locally with docker runAWS Lambda Container Image for Ruby Code -- 如何使用 docker run 在本地进行测试
【发布时间】:2021-03-29 10:52:12
【问题描述】:

我正在将 Ruby 2.7 Lambda 从 zip 文件部署迁移到容器映像部署。

当我将容器部署到 AWS Lambda 时,容器的行为与我希望的一样。

当我尝试使用 docker run {my-image-name} 在本地测试相同的图像时,我遇到了 2 个问题

  1. 不能以相同的方式从事件对象访问参数
  2. 返回标头和状态代码的处理方式与从 Lambda 处理的方式不同

我的问题

  • 我是否需要将其他内容捆绑到我的 dockerfile 中以协助 Lambda 模拟?
  • 我需要在我的 dockerfile 中使用不同的入口点吗?
  • 我找到了“AWS Lambda 运行时接口模拟器”的文档,但我不清楚它是否旨在帮助解决我遇到的问题。

这是我正在尝试测试的简化版本。

Dockerfile

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

COPY * ./

RUN bundle install 

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

宝石文件

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 中运行

docker run --rm --name lsample -p 9000:8080 -d {my-image-name}

对本地 docker 的 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 请求到本地 docker

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

【问题讨论】:

  • 您似乎正在比较通过 AWS 上的 API 网关/负载均衡器调用的 Lambda 函数与本地运行时接口模拟器。后者,虽然暴露本地服务器没有前者的任何特性,但它所做的只是将 POST 请求的正文内容作为函数的event 参数传递。

标签: amazon-web-services aws-lambda


【解决方案1】:

创建一个 Sinatra 应用程序来模拟 Application Load Balancer 的操作

根据以下文档,我认为我需要模拟我的 lambda 代码前面的 AWS Application Load Balancer 执行的操作。见https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html

simulate-lambda-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

模拟-lambda-alb/Dockerfile

FROM ruby:2.7

RUN gem install bundler

COPY Gemfile Gemfile

RUN bundle install

COPY . .

EXPOSE 8091

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

docker-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 模拟应用负载均衡器

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

【讨论】:

    猜你喜欢
    • 2021-09-06
    • 1970-01-01
    • 2018-07-02
    • 2016-02-26
    • 1970-01-01
    • 2022-10-25
    • 2019-11-30
    • 2019-01-31
    • 1970-01-01
    相关资源
    最近更新 更多