python代码可以部署在AWS lambda中,但不能部署在localstack中

时间:2018-11-30 09:39:47

标签: python-3.x atlassian-localstack

我开发了一个python(v3.6)项目,该项目已部署并实际在我的 AWS生产平台中的无服务器lambda中工作。该项目使用以下依赖项:

- awscli==1.16.10
- boto3==1.9.0
- botocore==1.12.0
- psycopg2==2.7.5
- SQLAlchemy==1.2.11
- SQLAlchemy-Utils==0.33.3
- jsonschema==2.6.0

现在,我想使用localstack在可以调用的lambda中部署该项目,以测试我的调用代码(而不是我的项目代码,该代码实际上有效!)

要部署项目,首先我要安装依赖项并创建一个zip文件:

pip install -r requirements.txt --upgrade -t ./
chmod -R 755 .
zip -r lambda.zip .

然后,我使用命令(运行本地堆栈):

aws lambda --region eu-east-1 --endpoint localhost:4574 \
    create-function --function-name mylambda \
    --zip-file fileb://lambda.zip

但是,它从localstack返回一个错误:

....
localstack_1  |     from functools32 import lru_cache
localstack_1  | ImportError: No module named functools32
....
localstack_1  |     raise Exception('Unable to get handler function from lambda code.', e)
localstack_1  | Exception: ('Unable to get handler function from lambda code.', ImportError('No module named functools32',))

jsonschema使用模块functools32,仅适用于python 2.7或<= 3.2。我正在使用python 3.6,所以无法安装。此外,当我在AWS生产平台中部署相同的lambda.zip时,我没有出现此错误。

我真的不知道如何解决这个问题。如果有人有想法要检查,我将非常感谢。

关于

1 个答案:

答案 0 :(得分:2)

您执行此操作的方式与我非常相似,除了在创建lambda函数时,我还附加了一些定义处理程序函数,运行时等的标志,所以我会说您的错误就在那里。话虽如此,我可以在AWS和Localstack上成功运行lambda,因此这是我的方法:

  1. 首先制作一个将安装要求的Dockerfile

    # Dockerfile
    FROM lambci/lambda:build-python3.7
    ENV REQPATH /root/requirements.txt
    COPY ./requirements.txt /root/requirements.txt
    pip3 install -i https://pypi.douban.com/simple -r ${REQPATH} --target=/opt/python/lib/python3.7/site-packages/
    RUN cd /opt && zip -r /root/lambda-layer.zip *
    
  2. 现在,构建映像并从容器中取出.zip文件:

    #!/bin/bash
    docker build -t lambda-layer:my_version ${NOCACHE} .
    id=$(docker create lambda-layer:my_version)
    docker cp $id:/root/lambda-layer.zip ~/lambda-layer.zip
    docker rm -v $id
    
  3. 现在,.zip文件可能是需要上传到AWS的文件,因为我直接在其网站上编写了lambda函数,但是对于Localstack,我们需要一个新的.zip文件,其内容与刚刚制作的文件相同,但是添加了一个用于lambda的python脚本。

  4. 在这种情况下,编写依赖于某些第三方模块的lambda脚本; requests

    # lambda.py
    import requests
    
    def handler(event, context):
        print("--- testing localstack lambda ---")
        print("event: ", event)
        print("context: ", context.__dict__)
        r = requests.get("http://192.168.xx.xx/path/")
        print("r: ", r)
        return {"foo": "bar"}
    
  5. 使用上述python脚本制作一个新的.zip文件:

    # shell
    $ cp lambda-layer.zip lambda-layer-localstack.zip
    $ zip -ur lambda-layer-localstack.zip lambda.py
    
    # Check contents on zip file contain the python 
    # dependencies and lambda function script
    $ unzip -l lambda-layer-localstack.zip
    Archive:  lambda-layer-localstack.zip
      Length      Date    Time    Name
    ---------  ---------- -----   ----
            0  2019-02-02 15:37   python/
          261  2019-02-02 15:43   lambda.py
    ---------                     -------
          261                     2 files
    
  6. 现在我们只需要在Localstack上创建该lambda函数

    $ awslocal --endpoint-url=http://192.168.xx.xx:4569 \
             lambda create-function \
             --function-name=function1 \
             --runtime=python3.7 \
             --role=r1 \
             --handler=lambda.handler
             --zip-file fileb://lambda-layer-localstack.zip
    
  7. 最后,测试它是否有效

    $ awslocal --endpoint-url=http://192.168.2.75:4569 \
             lambda invoke
             --function-name function1 result1.log
    {
        "StatusCode": 200
    }
    
    # On docker-compose logs (docker-compose logs -f)
    localstack_1  | --- testing localstack lambda ---
    localstack_1  | ('event: ', None)
    localstack_1  | ('context: ', {..})
    localstack_1  | ('r: ', <Response [200]>)