python 和无服务器框架的问题

Issues with python and the serverless framework

我想了解如何在一个 serverless.yml 中设置多个 python lambda 和一个阶跃函数,每个 python lambda 都有自己的依赖项。我的所有 lambda 函数都在阶跃函数的上下文中协作,以实现共同的目标。有了这个理由,将所有代码放在一个 serverless.yml 文件中对我来说是有意义的。 作为我许多小时的反复试验和阅读的一部分,我发现 The Serverless Frameworkserverless-python-requirements 插件有助于打包 python 依赖于 OS-specific [=] 的函数80=] 库,并且还允许分隔多个 requirements.txt 以防不同的 lambda 需要不同的依赖项。 所以此时我的问题是生成的包不包括我在 requirements.txt 中提供的依赖项,只要每个函数都有自己的 requirements.txt

这些是我的作品:

package.json

    {
  "engines": {
    "node": ">=10.0.0",
    "npm": ">=6.0.0"
  },
  "name": "example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "serverless-python-requirements": "^5.1.0"
  },
  "devDependencies": {
    "serverless": "^1.72.0"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "license": "ISC"
}

serverless.yml

service: example

frameworkVersion: ">=1.72.0 <2.0.0"

plugins:
  - serverless-python-requirements

custom:
  stage: "${opt:stage, env:SLS_STAGE, 'local'}"
  log_level: "${env:LOG_LEVEL, 'INFO'}"
  pythonRequirements:
    dockerizePip: true

provider:
  name: aws
  # profile: ${self:custom.profile}
  stage: ${self:custom.stage}
  runtime: python3.8
  environment:
    LOG_LEVEL: ${self:custom.log_level}

package:
  individually: true
  exclude:
    - ./**
  include:
    - vendored/**

functions:
  function1:
    # module: folder1
    handler: folder1/function1.handler
    package:
      include:
        - 'folder1/**'
    memorySize: 128
    timeout: 60
  function2:
    # module: folder2
    handler: folder2/function2.handler
    package:
      include:
        - 'folder2/**'
    memorySize: 128
    timeout: 60

最后,我的 2 个 python lambda 函数位于不同的文件夹中,其中一个需要特定的依赖项:

function1.py

import json
import logging
import os
import sys
import pyjokes

log_level = os.environ.get('LOG_LEVEL', 'INFO')
logging.root.setLevel(logging.getLevelName(log_level))
_logger = logging.getLogger(__name__)

class HandlerBaseError(Exception):
    '''Base error class'''

class ComponentIdentifierBaseError(HandlerBaseError):
    '''Base Component Identifier Error'''

def handler(event, context):
    '''Function entry'''
    _logger.debug('Event received: {}'.format(json.dumps(event)))

    body = {
        "message": "Go Serverless v1.0! Your function executed successfully!",
        "joke":pyjokes.get_joke()
    }

    resp = {
        'status': 'OK',
        "body": json.dumps(body)
    }

    _logger.debug('Response: {}'.format(json.dumps(resp)))
    return resp

if __name__ == "__main__":
    handler('', '')

requirements.txt

pyjokes==0.6.0

function2.py

import json
import logging
import os
import sys

log_level = os.environ.get('LOG_LEVEL', 'INFO')
logging.root.setLevel(logging.getLevelName(log_level))
_logger = logging.getLogger(__name__)

class HandlerBaseError(Exception):
    '''Base error class'''

class ElasticSearchPopulatorBaseError(HandlerBaseError):
    '''Base Component Identifier Error'''

def handler(event, context):
    '''Function entry'''
    _logger.debug('Event received: {}'.format(json.dumps(event)))

    resp = {
        'status': 'OK'
    }


    _logger.debug('Response: {}'.format(json.dumps(resp)))
    return resp

注意:我确实尝试在 serverless.xml 中使用 module+handler 关键字,正如在此 link 上所推荐的:ttps://github.com/UnitedIncome/serverless-python-requirements 没有任何成功

我注意到的一点是,如果我按如下方式使用模块+处理程序:

functions:
  function1:
    module: folder1
    handler: function1.handler
    package:
      include:
        - 'folder1/**'
    memorySize: 128
    timeout: 60

然后,当我在本地尝试 运行 函数时使用:serverless invoke local -f function1 --log 我收到一条错误消息:

ModuleNotFoundError: No module named 'function1'

此外,如果有人有多个具有不同 requirements.txt 的 lambda 的示例,我会非常感激,最好是与典型的 hello world 示例不同的东西,hello world 对我来说都很好用;),但在像这样的场景中,我想设置公共库,具有不同的依赖关系等,并使用一个公共的 serverless.yml 事情似乎分崩离析。同样,我的观点是这些 lambda 将在一步功能保护伞下一起运行,因此这里有很强的凝聚力,我认为它们的构建和部署应该在一个通用的无服务器服务下进行。

我最近使用 serverless-python-requirements 插件开发了一个类似的应用程序,该插件将多个 lambda 封装为一个堆栈的一部分,我在本地调用 lambda 函数时收到 ModuleNotFoundError,但它可以远程工作;但是,当我从我的 serverless.yml 文件中删除 module 参数时,我能够在本地调用但随后它因远程执行而中断。

我已经能够通过在 serverless.yml 中设置路径前缀找到解决方法:

functions:
  LambdaTest:
    handler: ${env:HANDLER_PATH_PREFIX, ""}handler.handler
    module: src/test_lambda
    package:
      include:
        - src/test_lambda/**

当我在本地调用该函数时,我将环境变量添加到我的命令中:

HANDLER_PATH_PREFIX=src/test_lambda/ ./node_modules/serverless/bin/serverless.js invoke local -f LambdaTest -p ./tests/resources/base_event.yml

我在 AWS 中调用函数时没有包含环境变量。

为了让它工作,我需要添加一个 init.py 文件到我的 lambda 函数所在的根目录,代码如下(取自 this solution) 以便我包含在 lambda 目录中存在的代码中的任何模块(例如 some_module -- 请参阅下面的目录树):

import os
import sys

sys.path.append(os.path.dirname(os.path.realpath(__file__)))

我的 lambda 的目录结构:

src/
└── test_lambda
    ├── __init__.py <=== add the code to this one
    ├── handler.py
    ├── requirements.txt
    └── some_module
        ├── __init__.py
        └── example.py

关于您关于使用不同 requirements.txt 文件的 lambda 的问题——我使用 individually 参数,如下所示:

package:
  individually: true
  include:
    - infra/**
  exclude:
    - "**/*"

在每个 requirements.txt 的每个 lambda 中,我使用 -r 选项引用一个单独的 requirements.txt 文件,该文件驻留在我的项目的基本目录中——这个文件包含的库对于所有 lambda 都是通用的,因此当 Serverless 为每个 lambda 安装包时,它也会包含我的 ./requirements.txt 文件中包含的包。

我已经将这个解决方案包含在一个关于 serverless-python-requirements 插件 in GitHub 的问题中,如果 module 参数的这种行为结果是一个错误。

希望对您有所帮助,如果您需要任何说明,请告诉我。