如何在 AWS CDK 创建的 Python Lambda 函数中安装外部模块?

Jam*_*mie 7 python python-module aws-cloudformation aws-lambda aws-cdk

我在 Cloud9 中使用 Python AWS CDK,我正在部署一个简单的 Lambda 函数当对象上传到 S3 存储桶(也由 CDK 创建)时,该函数应该向 Atlassian 的 API发送 API 请求。这是我的 CDK 堆栈代码:

from aws_cdk import core
from aws_cdk import aws_s3
from aws_cdk import aws_lambda
from aws_cdk.aws_lambda_event_sources import S3EventSource


class JiraPythonStack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here
        jira_bucket = aws_s3.Bucket(self,
                                    "JiraBucket",
                                    encryption=aws_s3.BucketEncryption.KMS)

        event_lambda = aws_lambda.Function(
            self,
            "JiraFileLambda",
            code=aws_lambda.Code.asset("lambda"),
            handler='JiraFileLambda.handler',
            runtime=aws_lambda.Runtime.PYTHON_3_6,
            function_name="JiraPythonFromCDK")

        event_lambda.add_event_source(
            S3EventSource(jira_bucket,
                          events=[aws_s3.EventType.OBJECT_CREATED]))

Run Code Online (Sandbox Code Playgroud)

lambda 函数代码使用requests我导入的模块。但是,当我检查 CloudWatch 日志并测试 lambda 函数时 - 我得到:

无法导入模块“JiraFileLambda”:没有名为“requests”的模块

我的问题是:如何通过 Python CDK 安装请求模块?

我已经在网上环顾四周并找到了这个。但它似乎直接修改了 lambda 函数,这会导致堆栈漂移(有人告诉我这对 IaaS 来说很糟糕)。我也查看了 AWS CDK 文档,但没有发现任何提及外部模块/库的内容(我现在正在对其进行彻底检查)有人知道我如何解决这个问题吗?

编辑: 看来我不是唯一一个寻找这个的人

这是提出的另一个 GitHub 问题。

lxo*_*xop 42

甚至没有必要使用 CDK 中的实验性 PythonLambda 功能 - CDK 内置支持将依赖项构建到简单的 Lambda 包(而不是 docker 映像)中。它使用 docker 进行构建,但最终结果仍然是一个简单的文件压缩包。文档在此处显示:https://docs.aws.amazon.com/cdk/api/latest/docs/aws-lambda-readme.html#bundling-asset-code;要点是:

new Function(this, 'Function', {
  code: Code.fromAsset(path.join(__dirname, 'my-python-handler'), {
    bundling: {
      image: Runtime.PYTHON_3_9.bundlingImage,
      command: [
        'bash', '-c',
        'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output'
      ],
    },
  }),
  runtime: Runtime.PYTHON_3_9,
  handler: 'index.handler',
});
Run Code Online (Sandbox Code Playgroud)

我在我的 CDK 部署中使用了这个精确的配置,并且效果很好。

对于Python来说,这很简单

aws_lambda.Function(
    self,
    "Function",
    runtime=aws_lambda.Runtime.PYTHON_3_9,
    handler="index.handler",
    code=aws_lambda.Code.from_asset(
        "function_source_dir",
        bundling=core.BundlingOptions(
            image=aws_lambda.Runtime.PYTHON_3_9.bundling_image,
            command=[
                "bash", "-c",
                "pip install --no-cache -r requirements.txt -t /asset-output && cp -au . /asset-output"
            ],
        ),
    ),
)
Run Code Online (Sandbox Code Playgroud)

  • 是的...这是正确的答案。只为一些简单的包做一层是行不通的。 (3认同)
  • 就我而言,我还需要在安装之前升级 pip,由于权限问题,这不起作用,所以我还需要将 `user="root"` 添加到 BundlingOptions (3认同)
  • 借调了。这个解决方案需要更多的赞成票, (2认同)

Jam*_*mie 12

更新:

现在看起来 CDK 中好像有一种新型(实验性)Lambda 函数,称为PythonFunction。它的Python 文档在这里。这包括支持添加一个requirements.txt文件,该文件使用 docker 容器将它们添加到您的函数中。在此处查看更多详细信息。具体来说:

如果入口路径中存在 requirements.txt 或 Pipfile,则该构造将根据运行时在 Lambda 兼容的 Docker 容器中安装所有必需的模块。

原答案:

所以这是我的经理写的很棒的代码,我们现在使用:


    def create_dependencies_layer(self, project_name, function_name: str) -> aws_lambda.LayerVersion:
        requirements_file = "lambda_dependencies/" + function_name + ".txt"
        output_dir = ".lambda_dependencies/" + function_name
        
        # Install requirements for layer in the output_dir
        if not os.environ.get("SKIP_PIP"):
            # Note: Pip will create the output dir if it does not exist
            subprocess.check_call(
                f"pip install -r {requirements_file} -t {output_dir}/python".split()
            )
        return aws_lambda.LayerVersion(
            self,
            project_name + "-" + function_name + "-dependencies",
            code=aws_lambda.Code.from_asset(output_dir)
        )

Run Code Online (Sandbox Code Playgroud)

它实际上是作为方法的 Stack 类的一部分(不在init 内)。我们在这里设置它的方式是我们有一个名为的文件夹lambda_dependencies,其中包含我们正在部署的每个 lambda 函数的文本文件,它只有一个依赖项列表,例如requirements.txt.

为了利用此代码,我们在 lambda 函数定义中包含如下内容:


        get_data_lambda = aws_lambda.Function(
            self,
            .....
            layers=[self.create_dependencies_layer(PROJECT_NAME, GET_DATA_LAMBDA_NAME)]
        )

Run Code Online (Sandbox Code Playgroud)


Kan*_*ane 7

在通过 CDK 部署 lambda 之前,您应该在本地安装 lambda 的依赖项。CDK 不知道如何安装依赖项以及应该安装哪些库。

在你的情况下,你应该在执行之前安装依赖请求和其他库cdk deploy

例如,

pip install requests --target ./asset/package
Run Code Online (Sandbox Code Playgroud)

一个例子供参考。