【问题标题】:"Runtime.ImportModuleError" trying to access npm package in an AWS lambda function using layers“Runtime.ImportModuleError”尝试使用层访问 AWS lambda 函数中的 npm 包
【发布时间】:2020-03-29 17:03:56
【问题描述】:

我想在 AWS lambda 函数中使用 npm 包“请求”。

我正在尝试按照本文中概述的步骤进行操作:https://medium.com/@anjanava.biswas/nodejs-runtime-environment-with-aws-lambda-layers-f3914613e20e

我已经创建了一个这样的目录结构:

nodejs
│   package-lock.json
│   package.json
└───node_modules

我的 package.json 看起来像这样:

{
  "name": "my-package-name",
  "version": "1.0.0",
  "description": "whatever",
  "author": "My Name",
  "license": "MIT",
  "dependencies": {
    "request": "^2.88.0"
  }
}

据我从文章中可以看出,我应该对上面做的就是运行npm i,压缩目录,将其作为图层上传,然后将图层添加到我的 lambda 函数中。

我已经完成了所有这些,但是当我尝试测试我的功能时,我得到的只是:

{
  "errorType": "Runtime.ImportModuleError",
  "errorMessage": "Error: Cannot find module 'request'\nRequire stack:\n- /var/task/index.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js",
  "trace": [
    "Runtime.ImportModuleError: Error: Cannot find module 'request'",
    "Require stack:",
    ...

...就好像该层从未添加过一样。无论是否添加图层,错误都是完全相同的。如果需要解决某种权限问题,文章中没有任何内容表明这一点。

我尝试了一些不同的方法,例如我的 .zip 文件是否包含顶级目录“nodejs”或仅包含其内容。我尝试将"main": "index.js", 添加到我的package.json 中,并使用这样的index.js 文件:

export.modules.request = require('request');

...一切都无济于事。

我错过了什么?

【问题讨论】:

    标签: javascript node.js amazon-web-services aws-lambda aws-lambda-layers


    【解决方案1】:

    哦,我简直不敢相信就是这个!

    .zip 文件的顶级目录必须从字面上命名为“nodejs”!我使用了不同的名称,只是在本文中将其改回“nodejs”以更通用,但目录名称一直是真正的问题。

    叹息。

    【讨论】:

    • 和你一样,已经为此苦苦挣扎了好几个小时,并且 100% 有效。觉得自己是个傻瓜:)谢谢!
    • 等等,你到底做了什么?
    • @joeCarpenter,我刚刚将 .zip 文件中的顶级目录的名称更改为 nodejs,就像我在示例代码中看到的那样,而不是其他名称我会选择。在我在这里的原始帖子中,它说nodejs 不是因为那是我真正一直在使用的,而是因为我试图让我的个人代码看起来更通用......没有意识到我正在偶然发现需要的真正修复。
    【解决方案2】:

    通常,它与里面的文件夹/文件的名称有关。如果这些文件被引用到其他地方,它也会在那里渗透和抱怨。只要彻底检查文件夹结构,你就能抓到小偷。我挣扎了一天才弄明白,这是一个愚蠢的错字。

    【讨论】:

    • 这更像是一个评论而不是一个答案。
    【解决方案3】:

    使用带有加密密钥 (KMS) 和环境变量的 lambda 函数从 RDS 访问表数据

    第 1 步:- 首先在 KMS(密钥管理服务 (KMS))中启用密钥

    查看您的关键政策并完成!使用 KMS 创建

    {
    "Id": "key-consolepolicy-3",
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Enable IAM User Permissions",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::163806924483:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "Allow access for Key Administrators",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::163806924483:user/User1@gmail.com"
            },
            "Action": [
                "kms:Create*",
                "kms:Describe*",
                "kms:Enable*",
                "kms:List*",
                "kms:Put*",
                "kms:Update*",
                "kms:Revoke*",
                "kms:Disable*",
                "kms:Get*",
                "kms:Delete*",
                "kms:TagResource",
                "kms:UntagResource",
                "kms:ScheduleKeyDeletion",
                "kms:CancelKeyDeletion"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::163806924483:user/User1@gmail.com",
                    "arn:aws:iam::163806924483:user/User2@gmail.com",
                    "arn:aws:iam::163806924483:user/User3@gmail.com"
                ]
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt",
                "kms:ReEncrypt*",
                "kms:GenerateDataKey*",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::163806924483:user/User1.dilip@gmail.com",
                    "arn:aws:iam::163806924483:user/User2@gmail.com",
                    "arn:aws:iam::163806924483:user/User3@gmail.com"
                ]
            },
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                "Bool": {
                    "kms:GrantIsForAWSResource": "true"
                }
            }
        }
    ]
    }
    

    步骤:- 2在 IAM 中为 KMS 分配给您的每个 lambda 函数创建一个策略

    "StringEquals": {
                "kms:EncryptionContext:LambdaFunctionName": [
                    "LambdaFunction-1",
                    "LambdaFunction-2",
                    "LambdaFunction-3"
                ]
            }
    

    步骤 3:- 将步骤 2 中创建的策略分配给您的默认 lambda 角色(需要创建第一个 Lambda 以获得默认 lambda 角色)

    第 4 步:- 创建 lambda 函数

    Node.js lambda 函数代码

    const mysql = require('mysql');
    const aws = require("aws-sdk");
    
    
    const functionName = process.env.AWS_LAMBDA_FUNCTION_NAME;
    let res;
    let response={};
    exports.handler = async(event) => {
    reset_globals();
    
    // load env variables
    const rds_user = await kms_decrypt(process.env.RDS_USERNAME);
    const rds_pwd = await kms_decrypt(process.env.RDS_PASSWORD)
    
    // setup rds connection
    var db_connection = await mysql.createConnection({
        host: process.env.RDS_HOSTNAME,
        user: rds_user,
        password: rds_pwd,
        port: process.env.RDS_PORT,
        database: process.env.RDS_DATABASE
    });
    
    var sqlQuery = `SELECT doc_id from documents`;
    await getValues(db_connection,sqlQuery);
    
    }
    
    async function getValues(db_connection,sql) {
    await new Promise((resolve, reject) => {
        db_connection.query(sql, function (err, result) {
            if (err) {
                response = {statusCode: 500, body:{message:"Database Connection Failed", 
                 error: err}};
                console.log(response);
                resolve();
            }
            else {
               
                console.log("Number of records retrieved: " + JSON.stringify(result));
                res = result;
               
                resolve();
            }
        });
        });
    }
    
    async function kms_decrypt(encrypted) {
    const kms = new aws.KMS();
    const req = { CiphertextBlob: Buffer.from(encrypted, 'base64'), EncryptionContext: { 
    LambdaFunctionName: functionName } };
    const decrypted = await kms.decrypt(req).promise();
    let cred = decrypted.Plaintext.toString('ascii');
    return cred;
    }
    
    
    function reset_globals() {
    res = (function () { return; })();
    response = {};
    }
    

    现在您应该在 Lambda 中看到 KMS。

    第五步:-设置环境变量并加密。

    Lambda -> 函数 -> 配置 -> 环境变量 -> 编辑

    RDS_DATABASE 文档

    RDS_HOSTNAME docrds-library.c1k3kcldebmp.us-east-1.rds.amazonaws.com

    RDS_PASSWORD root123

    RDS_PORT 3306

    RDS_USERNAME 管理员

    在 Lambda 函数中解密加密的环境变量,使用下面的代码

    function kms_decrypt(encrypted) {
    const kms = new aws.KMS();
    const req = { CiphertextBlob: Buffer.from(encrypted, 'base64'), EncryptionContext: { 
    LambdaFunctionName: functionName } };
    const decrypted = await kms.decrypt(req).promise();
    let cred = decrypted.Plaintext.toString('ascii');
    return cred;
    }
    

    我的 RDS 文档表如下所示:-

    我在 lambda 函数中使用 sqlQuery 访问列 doc_id

    var sqlQuery = `SELECT doc_id from documents`;
    

    测试 lambda 函数后,我得到以下输出。

    如果你得到SQL导入错误,那么必须添加一个层。

    errorType": "Runtime.ImportModuleError",
    "errorMessage": "Error: Cannot find module 'mysql'\nRequire stack:\n- 
    /var/task/index.js\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js",
     "trace": [
    "Runtime.ImportModuleError: Error: Cannot find module 'mysql'",
    

    您可以配置您的 Lambda 函数以使用额外的代码和 层形式的内容。图层是一个 ZIP 存档,其中包含 库、自定义运行时或其他依赖项。有了图层,你 可以在你的函数中使用库而不需要将它们包含在 你的部署包。

    要在层中包含库,请将它们放在目录结构中 与您的编程语言相对应。

    Node.js – nodejs/node_modules

    Python - 蟒蛇

    Ruby – ruby​​/gems/2.5.0

    Java – java/lib

    首先创建一个包含 mysql 存档的 zip 存档。

    首先创建一个 react-project

    然后在终端 $project-path > npm init

    然后 $project-path > npm install mysql

    您应该会看到 node_modules 文件夹已创建。

    压缩 node_modules 该文件夹并上传到图层,如下所示。

    然后,转到 Lambda--> 层-->创建层。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-06
      相关资源
      最近更新 更多