如何在 AWS Lambda 中加载 npm 模块?

250

我使用基于Web的编辑器创建了几个Lambda函数。目前为止一切顺利。现在我想开始使用模块(例如Q用于Promises)来扩展这些函数。我无法弄清楚如何将这些模块传递到Lambda,以便它们可以被我的函数使用。

我已经阅读了在AWS Lambda中使用软件包和本地nodejs模块,但似乎需要设置EC2并从那里运行Lambda函数。在创建函数时有一种上传zip文件的机制,但似乎涉及发送本地开发的函数。由于我正在使用基于Web的编辑器工作,因此这似乎是一种奇怪的工作流程。

我该如何简单地部署一些模块以供我的Lambda函数使用?


9
这个链接中已经详细解释了全部内容 - http://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html。 - arcseldon
10个回答

302

如果你没有上传.zip文件,是无法加载 NPM 模块的,但你可以用两个快速的命令行来完成这个过程。

以下是具体步骤:

  1. 将 Lambda 函数文件放入单独的目录中。因为你要本地安装 npm 包,而且需要隔离和测试将要上传到 Lambda 的内容。

  2. 通过在第一步创建的 Lambda 目录下执行 npm install packageName 命令来本地安装 NPM 包。

  3. 确保本地运行时函数正常工作:node lambdaFunc.js(你可以简单地注释掉代码中的两行 export.handler 来适应本地运行 Node)。

  4. 进入 Lambda 文件夹并压缩目录中的内容,确保不包括目录本身。

zip -r lambdaFunc.zip .
  • 如果您已经安装了aws-cli,我建议这样做可以让您的生活更加轻松,您现在可以输入以下命令:

  • aws lambda update-function-code --function-name lambdaFunc \
    --zip-file fileb://~/path/to/your/lambdaFunc.zip
    

    (如果您像我一样想知道lambdaFunc部分上方没有引号)

  • 现在您可以在Lambda控制台中单击测试

  • 我建议为上述两个命令添加一个简短的别名。这是我在更长的Lambda更新命令中使用的内容:

  • alias up="aws lambda update-function-code --function-name lambdaFunc \
    --zip-file fileb://~/path/to/your/lambdaFunc.zip"
    

    19
    您可能需要明确指定目标区域:aws lambda update-function-code --function-name lambdaFunc --region eu-west-1 --zip-file fileb://~/path/to/your/lambdaFunc.zip - GreensterRox
    2
    虽然看起来需要更多的工作,但是通过这种方式构建lambda表达式真的是更好的方法...非常感谢! - Mike Perrenoud
    10
    在执行这些步骤时,我不得不使用 --zip-file fileb:// 而不是 --zip-file file:// - McLovin
    3
    请确保只压缩目录中的内容,并且要使用CLI(命令行界面)进行操作(使用Mac Finder中的“压缩”命令无效)。 - Yarin
    5
    这非常有用。但至少有两个问题需要解决才能使其对我起作用:1)对于我来说,它应该是--zip-file fileb:而不是file。2)在MacOS上,似乎需要使用3个斜杠,例如像这样:fileb:///Users/wio/Documents - Tobi
    显示剩余9条评论

    65
    为了在Lambda中包含npm模块,需要一个.zip文件。你真的不应该在Lambda Web编辑器中使用任何生产代码,就像任何生产代码一样,你应该在本地开发、提交到git等。
    我的流程:
    1)我的Lambda函数通常是较大项目的辅助工具,因此我在其中创建一个/aws/lambdas目录来存放它们。
    2)每个单独的lambda目录都包含一个index.js文件,其中包含函数代码,一个定义依赖项的package.json文件和一个/node_modules子目录。(package.json文件不被Lambda使用,只是为了我们可以在本地运行npm install命令。) package.json:
    {
      "name": "my_lambda",
      "dependencies": {
        "svg2png": "^4.1.1"
      }
    }
    

    3)我在.gitignore中忽略了所有的node_modules目录和.zip文件,以便于通过npm安装生成的文件和压缩文件不会混乱我们的存储库。

    .gitignore:


    .gitignore:

    # Ignore node_modules
    **/node_modules
    
    # Ignore any zip files
    *.zip
    

    4) 我在目录下执行npm install命令安装模块,并在本地开发/测试该函数。

    5) 我将lambda目录压缩为.zip文件并通过控制台上传。

    (重要提示:不要使用Mac Finder中的“压缩”工具压缩文件!您必须从目录根目录内的CLI运行zip命令-请参见这里)

    zip -r ../yourfilename.zip * 
    

    注意:

    如果您在Mac本地安装node模块,由于一些特定于平台的模块可能在部署到Lambda的基于Linux的环境时失败,所以您可能会遇到问题。(请参见https://dev59.com/2F0a5IYBdhLWcg3wva16#29994851)

    解决方法是在使用与您正在使用的Lambda Node.js运行时对应的AMI启动的EC2实例上编译这些模块(请参见Lambda运行时及其相应的AMI列表)。


    另请参见AWS Lambda中Node.js的部署包 - AWS Lambda


    56

    1
    直到此刻我才知道图层的存在。谢谢Eldad! - mecograph
    1
    为什么不使用AWS Toolkit?似乎它试图接管“所有这些”?(文档中关于如何完成所有这些的说明存在一些令人沮丧的分裂... a)基于Web的编辑器b)手动.zip上传c)SAM d)现在的层e)AWS Toolkit...作为开发人员,这真是太可怕了。) - Don Cheadle
    现在感觉这应该是被接受的答案了。 - Karthik RP

    11
    希望这可以帮到你,使用Serverless框架,你可以像这样做:
    1. 在你的serverless.yml文件中添加以下内容:
        plugins:
          - serverless-webpack
        custom:
          webpackIncludeModules:
            forceInclude:
              - <your package name> (for example: node-fetch)
    
    1. 接下来创建您的 Lambda 函数,通过 serverless deploy 部署它,包含在 serverless.yml 中的软件包将为您提供。

    有关无服务器的更多信息:使用 AWS 配置 Serverless 框架


    1
    你需要先安装它,使用命令 serverless plugin install --name pluginName - Liad Livnat

    9

    在花了几个小时研究Parcel后,我发现它似乎对在浏览器中运行有一些假设(即使我告诉它使用 engine: node)。

    相反:


    esbuild

    更容易且更快的方法是使用 esbuild

    只需运行 npm add --save-dev esbuild,并将以下脚本添加到您的 package.json 中:

    {
      ...
      "scripts": {
        "build": "esbuild --bundle --minify --platform=node --target=node12 --outdir=build main.js",
        "export": "cd build && zip main.js.zip main.js"
      },
      ...
      "devDependencies": {
        "esbuild": "^0.11.19",
        ...
      }
    }
    

    这使得我可以使用aws-sdk,同时实现了tree-shaking和minifying,还能够安装其他依赖项,如jest和eslint,而不必打包整个node_modules文件夹。

    要在CI中构建软件包,只需执行以下操作:npm ci && npm run build && npm run export

    然后,文件build/main.js.zip将包含您需要的所有内容!


    2
    我差点忽略了这个解决方案,因为最初的“包裹”段落并不是很相关,但除此之外,这个解决方案非常棒;非常简单而且有效。 - atlas_scoffed
    这段代码无法与使用硬编码引用的Sharp库一起工作:require(../build/Release/sharp-${platformAndArch}.node); 当启用捆绑时,main.js 正试图从相对路径 ../build/Release 访问此文件。 - MTP

    5

    现在许多 IDE,例如 VSC,都可以安装 AWS 扩展程序,只需从那里单击上传即可,无需键入所有命令和区域。

    这是一个例子:

    enter image description here


    2
    AWS VS Code 扩展可以在这里找到。 - Bjorn Liza
    我看不到与NPM包的任何关联,就像问题中所描述的那样。 - Oded BD

    2

    npm模块必须被打包到您的nodejs包中,并以zip格式上传到AWS Lambda Layers,然后您需要按照以下方式引用您的模块/ js并使用其中可用的方法。

    const mymodule = require('/opt/nodejs/MyLogger');


    2

    如果您需要管理多个AWS资源,使用AWS CDK部署Lambda函数可能是一个不错的选择。它是一款基础设施即代码工具,可部署AWS资源并使用CloudFormation。要设置CDK,请参见使用AWS CDK入门

    一旦您设置了CDK,就可以创建Function构造函数,并使用其lambda.Code.fromAsset轻松打包源代码(包括node_modules),并将其用作Function的代码。

    import * as lambda from "aws-cdk-lib/aws-lambda";
    import * as path from "path";
    
    export class MyStack extends cdk.Stack {
      constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    
        const lambdaFunc = new lambda.Function(this, "lambdaFunc", {
          code: lambda.Code.fromAsset(path.join(__dirname, "..", "..", "project-containing-node-modules")),
          ...
        });
    
      }
    }
    

    然后使用cdk deploy将其部署到您的AWS帐户。

    如果您要在多个Lambda之间使用相同的node_modules并且不想上传重复的依赖项,则CDK还支持Lambda层


    1
    这是一个有些旧的问题,但它帮助我找到了一种非常简单的方法来为Alexa技能添加新的Lambda依赖项。
    与JohnAllen的答案类似,您需要在本地计算机上创建一个文件夹,随意命名(这是任意的):
    mkdir lambdaFunc
    cd lambdaFunc
    

    一旦进入您的文件夹,使用npm安装必要的软件包。 对我来说,我需要解析ISO8601持续时间(我的命令是npm install iso8601-duration):

    npm install <your-package-here>
    

    安装完成后,请退出该目录并进行压缩。在Alexa技能开发者控制台中打开您的Alexa技能,然后选择“导入代码”选项。从这里,您将上传您的.zip文件,并选择所有代码:

    Import Lambda Code in Alexa Skill Developer Console

    Select all code in .zip file

    就是这样!然后你可以像我一样导入代码:

    const DateConverter = require('iso8601-duration');
    

    0
    AWS CDK对此有一个很好的解决方案。有一个名为NodejsFunction的lambda构造函数。它使用esbuild将您的代码及其依赖项打包成一个单独的资源,当您“部署”应用程序时,它会被上传为一个zip文件。
    您只需要提供包含处理程序函数的文件的路径即可:
    const { Stack } = require('aws-cdk-lib');
    const lambdaNodeJs = require('aws-cdk-lib/aws-lambda-nodejs');
    const path = require("path");
    
    class CdkStack extends Stack {
        constructor(scope, id, props) {
            super(scope, id, props);
    
            const myLambda = new lambdaNodeJs.NodejsFunction(this, "my-lambda-id", {
                functionName: 'my-function-name',
                entry: path.join(path.join(__dirname, '/../../path/to/handler.js')),
                handler: 'handler-function-name'
                // rest of the config.
            });
        }
    }
    

    确保在lambda代码的package.json文件中将esbuild作为依赖项,并且一切就绪。

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