AWS SAM:如何在Lambda函数之间共享文件

7

我正在使用AWS SAM(无服务器应用程序模型)在API Gateway环境下构建Python 3.6 Lambda代码。因此,我有一个单独的template.yaml文件,可以创建多个Lambda函数。它们被组织到项目中各自的子目录中。Lambda还共享几个常见的文件,这些文件保存在共享文件夹中。

project-home
 -lambda_a_dir
   -lambda_a.py
 -lambda_b_dir
   -lambda_b.py
 -shared_dir
   -shared.py

问题在于Pycharm可以明显看到shared.py,但SAM无法识别共享文件,并出现以下错误: Unable to import module 'lambdaA':No module named 'shared'如果我将shared.py文件的副本移动到每个lambda目录中,Pycharm和SAM都很高兴,我可以构建/部署到AWS。
我的问题是:如何使用共享目录中的共享文件构建SAM模板?
到目前为止,我尝试过:

  • 符号链接和MacOS别名。
  • 各种CodeUri替代方案。
  • __init__setup.py的本地包。(我不能使用公共包,因为代码是私有的,不能放在公共存储库上。)

这是我的模板文件:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  lambdaA:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: ./lambda_a_dir/
      Handler: lambda_a.lambda_handler
      Runtime: python3.6
  lambdaB:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: ./lambda_b_dir/
      Handler: lambda_b.lambda_handler
      Runtime: python3.6

3
你应该看看 AWS Lambda Layers。将shared_dir内容放在一个单独的层中应该能解决问题。 - Dunedan
1
值得一提的是:AWS CLI团队已经收到了一个问题和一个PR,建议aws cloudformation package命令应该遵循符号链接。 - matsev
@Dunedan,你的回答是正确的。如果你把它写成一个答案,我会给你积分。 - Hephaestus
1
由于您已经在问题中得到了完整的答案,我建议您将此部分拆分出来,将其转化为实际答案并将其标记为接受的答案。 - Dunedan
4个回答

6

根据 @Dunedan 的建议,我为每个 Lambda 函数创建了一个 Layers 对象,并使用共享代码,这有效地将这些程序添加到了这些函数的 PythonPath 中。我还在 API 模板定义中使用了新的 Layers 属性添加了以下内容:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  lambdaA:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: ./lambda_a_dir/
      Handler: lambda_a.lambda_handler
      Runtime: python3.6
      Layers: 
        - arn:aws:lambda:us-west-1:012345678:layer:my_shared_zip:1
  lambdaB:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: ./lambda_b_dir/
      Handler: lambda_b.lambda_handler
      Runtime: python3.6
      Layers: 
        - arn:aws:lambda:us-west-1:012345678:layer:my_shared_zip:1

请注意,在上传前需要将代码压缩,并且需要有以下的目录结构,其中代码位于以语言名称命名的目录内。在这种情况下,因为我使用的是Python,所以代码需要放在名为python的目录中,然后将python目录压缩:
my_shared_zip.zip
 -python
   -shared.py
   -other_shared.py
   -more_shared.py

最后注意事项。虽然理想情况下,应该通过sam deploy命令直接将此shared-python目录部署到Layer对象中,但我发现AWS SAM CLI对Layers的支持还很新,而且存在许多缺陷,因此在这一点上它是不起作用的。希望在未来的几个月里它能够得到修复。与此同时,我需要手动安装新版本的共享zip文件。哎。


3
图层解决方案看起来像一个hack。 我尝试创建指向"shared"文件夹的符号链接,它成功地与我的lambda函数一起打包了共享文件夹。
cd lambda_a_dir
ln -s ../shared

1
我认为这是共享代码与重复代码的问题。使用Layers,同一层可以附加(共享)到数十个Lambda函数上,并且很容易确认它们都在共享同一层(因为Layers具有版本控制)。使用符号链接解决方案,每个Lambda函数将拥有其自己的“共享”文件的私有副本,从而引发了每个lambda正在使用哪些代码的问题。话虽如此,我开始认为容器(使用ECR / ECS)可能更容易管理,但我仍在研究中。 - Hephaestus
1
百分之百正确!个人而言,我更喜欢将所有必需的代码嵌入到 zip 包内作为函数。"symlink" 解决方案的小缺陷是:chalice deploy 不会跟随符号链接 :( - MrKsn
这对于使用CDK的Python lambda不起作用。 :'( - Natacha

0

你尝试过使用Rocketsam CLI吗?它可以解决这个问题(在构建期间自动创建符号链接来共享代码)。它还允许将YAML文件拆分,以便每个Lambda都可以拥有单独的YAML文件。


-2
为什么不直接取消独立的lambda_a_dirlambda_b_dir文件夹,而是将Lambda源代码文件(lambda_a.pylambda_b.py)放入根路径,即与shared/ 同一级别下? 我按照这种方式组织了我的SAM存储库,并且在访问不同Lambda之间的共享模块时没有任何问题。

在我看来,这个问题没有达到目的——如何在保持一些共享代码的同时,实际利用每个独立的 Lambda 的较小捆绑大小,而无需将所有 Lambda 捆绑在一起。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接