使用 Python Lambda 函数的层 - Amazon Lambda
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

使用 Python Lambda 函数的层

Lambda 层是包含补充代码或数据的 .zip 文件存档。层通常包含库依赖项、自定义运行时系统或配置文件。创建层涉及三个常见步骤:

  1. 打包层内容。此步骤需要创建 .zip 文件存档,其中包含要在函数中使用的依赖项。

  2. 在 Lambda 中创建层。

  3. 将层添加到函数。

本主题包含有关如何正确打包并创建具有外部库依赖项的 Python Lambda 层的步骤和指南。

先决条件

要完成本部分中的步骤,您必须满足以下条件:

在整个主题中,我们会引用 awsdocs GitHub 存储库中的 layer-python 示例应用程序。该应用程序包含用于下载依赖项并生成层的脚本。该应用程序还包含相应的函数,函数使用来自层的依赖项。创建层后,即可部署并调用相应的函数来验证一切是否正常运行。由于使用 Python 3.11 运行时系统来运行这些函数,因此这些层还必须与 Python 3.11 兼容。

layer-python 示例应用程序中,有两个示例:

  • 第一个示例展示如何将 requests 库打包到 Lambda 层中。layer/ 目录包含用于生成层的脚本。function/ 目录包含示例函数,用于帮助测试该层是否正常工作。本教程的大部分内容将演示如何创建并打包该层。

  • 第二个示例展示如何将 numpy 库打包到 Lambda 层中。layer-numpy/ 目录包含用于生成层的脚本。function-numpy/ 目录包含示例函数,用于帮助测试该层是否正常工作。有关如何创建并打包该层的示例,请参阅使用 manylinux Wheel 发行版

Python 层与 Amazon Linux 的兼容性

创建层的第一步是将所有层内容捆绑到.zip 文件存档中。由于 Lambda 函数在 Amazon Linux 上运行,因此层内容必须能够在 Linux 环境中编译和构建。

在 Python 中,除了源代码发行版外,大多数程序包还可作为 Wheel.whl 文件)使用。每个 Wheel 都是一种已构建的发行版,支持 Python 版本、操作系统和机器指令集的特定组合。

Wheel 有助于确保层与 Amazon Linux 兼容。下载依赖项时,如果可能,请下载通用 Wheel。(默认情况下,如果通用 Wheel 可用,则 pip 将安装通用 Wheel。) 通用 Wheel 包含 any 作为平台标签,表示与包括 Amazon Linux 在内的所有平台兼容。

在接下来的示例中,您要将 requests 库打包到 Lambda 层中。requests 库是可用作通用 Wheel 的示例程序包。

并非所有 Python 程序包都作为通用 Wheel 发行。例如,numpy 有多个 Wheel 发行版,每个版本都支持一组不同的平台。对于此类程序包,请下载 manylinux 发行版来确保与 Amazon Linux 兼容。有关如何打包此类层的详细说明,请参阅使用 manylinux Wheel 发行版

在极少数情况下,Python 程序包可能无法作为 Wheel 使用。如果只存在源代码发行版 (sdist),则建议在基于 Amazon Linux 2023 基本容器映像Docker 环境中安装并打包依赖项。如果想包含以其他语言(例如 C/C++)编写的自定义库,也推荐使用这种方法。此方法在 Docker 中模仿 Lambda 执行环境,可确保非 Python 程序包依赖项与 Amazon Linux 兼容。

Python 运行时系统的层路径

当您向函数添加层时,Lambda 会将层内容加载到该执行环境的 /opt 目录中。对于每个 Lambda 运行时系统,PATH 变量都包括 /opt 目录中的特定文件夹路径。为确保 PATH 变量能够获取层内容,层 .zip 文件应在以下文件夹路径中具有依赖项:

  • python

  • python/lib/python3.x/site-packages

例如,您在本教程中创建生成的层.zip 文件具有以下目录结构:

layer_content.zip └ python └ lib └ python3.11 └ site-packages └ requests └ <other_dependencies> (i.e. dependencies of the requests package) └ ...

requests 库位于 python/lib/python3.11/site-packages 目录中,位置正确。这可确保 Lambda 在函数调用期间可以找到该库。

打包层内容

在本示例中,您要将 Python requests 库打包到一个层 .zip 文件中。完成以下步骤,安装并打包层内容。

安装并打包层内容
  1. 克隆 aws-lambda-developer-guide GitHub 存储库,其中包含 sample-apps/layer-python 目录中需要的示例代码。

    git clone https://github.com/awsdocs/aws-lambda-developer-guide.git
  2. 导航到 layer-python 示例应用程序的 layer 目录。此目录包含用于正确创建并打包层的脚本。

    cd aws-lambda-developer-guide/sample-apps/layer-python/layer
  3. 检查 requirements.txt 文件。此文件定义了要包含在层中的依赖项,即 requests 库。您可以更新此文件,纳入要包含在层中的任何依赖项。

    例 requirements.txt
    requests==2.31.0
  4. 确保拥有运行这两个脚本的权限。

    chmod 744 1-install.sh && chmod 744 2-package.sh
  5. 使用以下命令运行 1-install.sh 脚本:

    ./1-install.sh

    此脚本使用 venv 来创建名为 create_layer 的 Python 虚拟环境,随后在 create_layer/lib/python3.11/site-packages 目录中安装所有必需的依赖项。

    例 1-install.sh
    python3.11 -m venv create_layer source create_layer/bin/activate pip install -r requirements.txt
  6. 使用以下命令运行 2-package.sh 脚本:

    ./2-package.sh

    此脚本将内容从 create_layer/lib 目录复制到名为 python 的新目录中,随后将 python 目录的内容压缩到一个名为 layer_content.zip 的文件中。这便是层的 .zip 文件。您可以解压缩文件,验证是否包含正确的文件结构,如 Python 运行时系统的层路径部分所示。

    例 2-package.sh
    mkdir python cp -r create_layer/lib python/ zip -r layer_content.zip python

创建层

在本部分,您会获取在上一部分中生成的 layer_content.zip 文件,将其作为 Lambda 层上传。您可以使用 Amazon Web Services Management Console 上传层,也可以通过 Amazon Command Line Interface(Amazon CLI)使用 Lambda API 上传层。上传层 .zip 文件时,在以下 PublishLayerVersion Amazon CLI 命令中,将 python3.11 指定为兼容的运行时系统,并将 arm64 指定为兼容的架构。

aws lambda publish-layer-version --layer-name python-requests-layer \ --zip-file fileb://layer_content.zip \ --compatible-runtimes python3.11 \ --compatible-architectures "arm64"

注意响应中的 LayerVersionArn,与 arn:aws:lambda:us-east-1:123456789012:layer:python-requests-layer:1 类似。在本教程的下一步中,在将层添加到函数时,您要用到此 Amazon 资源名称(ARN)。

将层添加到函数

在本部分,您要部署在函数代码中使用 requests 库的示例 Lambda 函数,然后附加该层。要部署该函数,您需要一个 Lambda 执行角色。如果目前没有执行角色,则按照可折叠部分中的步骤操作。若有,则跳至下一部分来部署函数。

创建执行角色
  1. 在 IAM 控制台中,打开 Roles(角色)页面

  2. 选择创建角色

  3. 创建具有以下属性的角色。

    • Trusted entity(可信任的实体)– Lambda

    • Permissions(权限)– AWSLambdaBasicExecutionRole

    • Role name(角色名称)– lambda-role

    AWSLambdaBasicExecutionRole 策略具有函数将日志写入 CloudWatch Logs 所需的权限。

部署 Lambda 函数
  1. 导航到 function/ 目录。如果当前在 layer/ 目录中,请运行以下命令:

    cd ../function
  2. 检查函数代码。函数会导入 requests 库,发出简单的 HTTP GET 请求,然后返回状态代码和正文。

    import requests def lambda_handler(event, context): print(f"Version of requests library: {requests.__version__}") request = requests.get('https://api.github.com/') return { 'statusCode': request.status_code, 'body': request.text }
  3. 使用以下命令创建 .zip 文件部署包:

    zip my_deployment_package.zip lambda_function.py
  4. 部署函数。在以下 Amazon CLI 命令中,将 --role 参数替换为执行角色 ARN:

    aws lambda create-function --function-name python_function_with_layer \ --runtime python3.11 \ --architectures "arm64" \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::123456789012:role/lambda-role \ --zip-file fileb://my_deployment_package.zip

此时,可以选择在附加层之前尝试调用函数。如果尝试该操作,之后应会收到导入错误消息,因为函数无法引用 requests 程序包。要调用函数,请使用以下 Amazon CLI 命令:

aws lambda invoke --function-name python_function_with_layer \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

应看到类似如下内容的输出:

{ "StatusCode": 200, "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST" }

要查看特定错误,请打开输出 response.json 文件。您会看到包含以下错误消息的 ImportModuleError

"errorMessage": "Unable to import module 'lambda_function': No module named 'requests'"

接下来,将层附加到函数。在以下 Amazon CLI 命令中,将 --layers 参数替换为之前记下的层版本 ARN:

aws lambda update-function-configuration --function-name python_function_with_layer \ --cli-binary-format raw-in-base64-out \ --layers "arn:aws:lambda:us-east-1:123456789012:layer:python-requests-layer:1"

最后,尝试使用以下 Amazon CLI 命令调用函数:

aws lambda invoke --function-name python_function_with_layer \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

应看到类似如下内容的输出:

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" }

输出 response.json 文件包含有关响应的详细信息。

除非您想要保留为本教程创建的资源,否则可立即将其删除。通过删除您不再使用的 Amazon 资源,可防止您的 Amazon Web Services 账户 产生不必要的费用。

删除 Lambda 层
  1. 打开 Lambda 控制台的 Layers page(层页面)。

  2. 选择您创建的层。

  3. 选择删除,然后再次选择删除

删除 Lambda 函数
  1. 打开 Lamba 控制台的 Functions(函数)页面

  2. 选择您创建的函数。

  3. 依次选择操作删除

  4. 在文本输入字段中键入 delete,然后选择删除

使用 manylinux Wheel 发行版

有时,要作为依赖项包含的程序包没有通用 Wheel(具体来说,就是没有 any 作为平台标签)。在这种情况下,请改为下载支持 manylinux 的 Wheel。此举可确保 Layer 库与 Amazon Linux 兼容。

numpy 是没有通用 Wheel 的程序包。如果要将 numpy 程序包包含在层中,则可以完成以下示例步骤来正确安装并打包层。

安装并打包层内容
  1. 克隆 aws-lambda-developer-guide GitHub 存储库,其中包含 sample-apps/layer-python 目录中需要的示例代码。

    git clone https://github.com/awsdocs/aws-lambda-developer-guide.git
  2. 导航到 layer-python 示例应用程序的 layer-numpy 目录。此目录包含用于正确创建并打包层的脚本。

    cd aws-lambda-developer-guide/sample-apps/layer-python/layer-numpy
  3. 检查 requirements.txt 文件。此文件定义了要包含在层中的依赖项,即 numpy 库。您可以指定与 Python 3.11、Amazon Linux 以及 x86_64 指令集兼容的 manylinux Wheel 发行版的 URL:

    例 requirements.txt
    https://files.pythonhosted.org/packages/3a/d0/edc009c27b406c4f9cbc79274d6e46d634d139075492ad055e3d68445925/numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
  4. 确保拥有运行这两个脚本的权限。

    chmod 744 1-install.sh && chmod 744 2-package.sh
  5. 使用以下命令运行 1-install.sh 脚本:

    ./1-install.sh

    此脚本使用 venv 来创建名为 create_layer 的 Python 虚拟环境,随后在 create_layer/lib/python3.11/site-packages 目录中安装所有必需的依赖项。在这种情况下,pip 命令有所不同,因为必须将 --platform 标签指定为 manylinux2014_x86_64。此操作告诉 pip 要安装正确的 manylinux Wheel,即便本地计算机使用的是 macOS 或 Windows 也是如此。

    例 1-install.sh
    python3.11 -m venv create_layer source create_layer/bin/activate pip install -r requirements.txt --platform=manylinux2014_x86_64 --only-binary=:all: --target ./create_layer/lib/python3.11/site-packages
  6. 使用以下命令运行 2-package.sh 脚本:

    ./2-package.sh

    此脚本将内容从 create_layer/lib 目录复制到名为 python 的新目录中,随后将 python 目录的内容压缩到一个名为 layer_content.zip 的文件中。这便是层的 .zip 文件。您可以解压缩文件,验证是否包含正确的文件结构,如 Python 运行时系统的层路径 部分所示。

    例 2-package.sh
    mkdir python cp -r create_layer/lib python/ zip -r layer_content.zip python

要将该层上传到 Lambda,请使用以下 PublishLayerVersion Amazon CLI 命令:

aws lambda publish-layer-version --layer-name python-numpy-layer \ --zip-file fileb://layer_content.zip \ --compatible-runtimes python3.11 \ --compatible-architectures "x86_64"

注意响应中的 LayerVersionArn,与 arn:aws:lambda:us-east-1:123456789012:layer:python-numpy-layer:1 类似。要验证层是否按预期运行,请在 function-numpy 目录中部署 Lambda 函数。

部署 Lambda 函数
  1. 导航到 function-numpy/ 目录。如果当前在 layer-numpy/ 目录中,请运行以下命令:

    cd ../function-numpy
  2. 检查函数代码。函数会导入 numpy 库,创建简单的 numpy 数组,然后返回虚拟状态代码和正文。

    import json import numpy as np def lambda_handler(event, context): x = np.arange(15, dtype=np.int64).reshape(3, 5) print(x) return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') }
  3. 使用以下命令创建 .zip 文件部署包:

    zip my_deployment_package.zip lambda_function.py
  4. 部署函数。在以下 Amazon CLI 命令中,将 --role 参数替换为执行角色 ARN:

    aws lambda create-function --function-name python_function_with_numpy \ --runtime python3.11 \ --handler lambda_function.lambda_handler \ --role arn:aws:iam::123456789012:role/lambda-role \ --zip-file fileb://my_deployment_package.zip

您也可以选择在附加层之前尝试调用函数。如果尝试该操作,之后应会收到导入错误消息,因为函数无法引用 numpy 程序包。要调用函数,请使用以下 Amazon CLI 命令:

aws lambda invoke --function-name python_function_with_numpy \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

应看到类似如下内容的输出:

{ "StatusCode": 200, "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST" }

要查看特定错误,请打开输出 response.json 文件。您会看到包含以下错误消息的 ImportModuleError

"errorMessage": "Unable to import module 'lambda_function': No module named 'numpy'"

接下来,将层附加到函数。在以下 Amazon CLI 命令中,将 --layers 参数替换为层版本 ARN:

aws lambda update-function-configuration --function-name python_function_with_numpy \ --cli-binary-format raw-in-base64-out \ --layers "arn:aws:lambda:us-east-1:123456789012:layer:python-requests-layer:1"

最后,尝试使用以下 Amazon CLI 命令调用函数:

aws lambda invoke --function-name python_function_with_numpy \ --cli-binary-format raw-in-base64-out \ --payload '{ "key": "value" }' response.json

应看到类似如下内容的输出:

{ "StatusCode": 200, "ExecutedVersion": "$LATEST" }

您可以检查函数日志,验证代码是否将 numpy 数组打印为标准输出。