AWS CDK - 如何在本地运行 API 和 Lambda?

Posted

技术标签:

【中文标题】AWS CDK - 如何在本地运行 API 和 Lambda?【英文标题】:AWS CDK - How to run API and Lambdas locally? 【发布时间】:2021-11-10 13:50:57 【问题描述】:

编辑:原来解决方案在文档中。我安装了沼泽标准普通“sam”,但我需要他们所谓的“公共预览版”AKA“sam-beta-cdk”。安装后,API 可以在本地使用sam-betacdk start-api 启动并且运行良好。虽然我很欣赏建议应该使用纯 TDD 来完成开发的答案,但我觉得这种更具交互性的手动模式也很有价值,因为它允许更快地探索问题空间。

我正在尝试使用 API Gateway、Lambdas 和 DynamoDB 使用 CDK + Typescript 构建我的第一个应用程序。我已经构建了几个 Lambdas 并部署了它们,它们在网络上运行良好。但是,我不希望将一分钟的部署周期和各种相关的 AWS 成本作为我工作流程的一部分。我想要的是能够在本地测试我的 API。

我一直在努力寻找有关如何执行此操作的文档。亚马逊似乎建议使用 SAM CLI here,这就是我一直在尝试的。

文档声称运行 sam local xyz 运行 cdk synth 以在 ./aws-sam/build 中进行“可以组装”,但我没有看到这方面的证据。相反,我得到的是 sam 找不到“template.yml”的投诉。所以我手动运行cdk synth > template.yml,它会在根文件夹中创建一个。然后我运行sam local start-api,它似乎很高兴启动。

然后我尝试使用 CURL:curl 'http://127.0.0.1:3000/test' 命中我的测试 lambda,我得到 "message":"Internal server error" 和一个巨大的丑陋堆栈跟踪在运行 sam local start-api 的控制台中

lambda 是这个...

exports.handler = async function() 
    console.log("WooHoo! Test handler ran")
    return statusCode: 200, headers: "Content-Type": "application/json", body: "Test handler ran!"

巨大的丑陋堆栈跟踪的开始......

Mounting /home/user/code/image-cache/asset.beeaa749e012b5921018077f0a5e4fc3ab271ef1c191bd12a82aa9a92148782e as /var/task:ro,delegated inside runtime container
START RequestId: 99f53642-b294-4ce5-a1b4-8c967db80ce1 Version: $LATEST
2021-09-15T12:33:37.086Z    undefined   ERROR   Uncaught Exception  "errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot find module 'test'\nRequire stack:\n- /var/runtime/UserFunction.js\n- /var/runtime/index.js","stack":["Runtime.ImportModuleError: Error: Cannot find module 'test'","Require stack:","- /var/runtime/UserFunction.js","- /var/runtime/index.js","    at _loadUserApp (/var/runtime/UserFunction.js:100:13)","    at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",

巨大丑陋的堆栈跟踪结束...

Invalid lambda response received: Lambda response must be valid json

所以看起来sam local start-api 找不到test 并抛出错误,这意味着API 网关没有得到有效的“lambda 响应”。到目前为止,这并没有帮助我解决问题:/ 它似乎确实意识到测试是一条路线,因为尝试命中其他端点给出了经典的"message":"Missing Authentication Token",但尽管我同时拥有functions/test.ts,但试图实现它却很难实现它和编译后的functions/test.js 存在。

我在我的 CDK 堆栈定义中定义了测试路由和处理程序,如下所示...

    const testLambda = new lambda.Function(this, "testLambdaHandler", 
      runtime: lambda.Runtime.NODEJS_14_X,
      code: lambda.Code.fromAsset("functions"),
      handler: "test.handler"
    )

    api.root
      .resourceForPath("test")
      .addMethod("GET", new apigateway.LambdaIntegration(testLambda))

我考虑过发布我的 template.yml,但这比大而丑陋的错误消息还要长,所以我没有。

所以我有三个问题(实际上是一百万,但我不想太厚脸皮!)

    这实际上是本地测试使用 CDK 制作的应用程序的规范方式吗 如果是这样,我哪里出错了? 如果不是,更好/正确的方法是什么?

【问题讨论】:

你好,@Roger。当cdk synth命令执行时,你能把它贴在这里template.yaml文件,以便我们检查正在创建的资源吗? @MateusArruda 当然,都在这里:github.com/Roger-Heathcote/image-cache 这很奇怪,但我有一个猜测:你的image-cache-stack.ts<rootDir>/lib 中,对吗?在addLambda 函数中,您指向一个名为“functions”的目录,但在您现在所在的文件中,没有名为functions 的目录。所以我认为您可以执行以下操作: 1. 使用code: lambda.Code.fromAsset("../../functions"),或者像this documentation 一样将根目录设置为函数。让我们知道这是否适合您。 感谢马特乌斯。我刚刚发现了问题,根本不是代码,我没有安装最新的“公共预览”版本的 sam。我被顶部的示例抛出,没有使用'sam-beta-cdk'。我安装了一切都很好。非常感谢您的宝贵时间! 我很高兴听到这个消息!我会继续关注,这样也不会发生在我身上 【参考方案1】:

您的文件目录一定有问题。您的 index.js 在哪里?如果生成template.json,目录是否正确? 还有在哪个目录下执行 Sam 本地命令?

测试无服务器应用程序的好处是您不必测试整个应用程序。您需要依靠 AWS,API 网关、dynamodb 和 lambda 可以完美运行。 您唯一需要测试的是您实现的逻辑。

在这里,您确保您的函数打印出一些内容并返回 200。这就是您所要做的。 研究 'jest' 来测试 js。

如果你想测试 cdk 你应该进入https://docs.aws.amazon.com/cdk/latest/guide/testing.html

“在本地运行 Aws”也不是好的做法。它与现实生活中的运行方式(即云)完全不同。您为此使用插件,为此使用工具...本地与云端不同。

如果您还有其他问题,请随时提问。

【讨论】:

我没有index.js,我的入口点是bin/image-cache.js。生成的模板位于我正在运行 sam 的根文件夹中。项目在这里:github.com/Roger-Heathcote/image-cache 谢谢。【参考方案2】:

Lambda 处理程序只是函数。它们不需要任何特殊的环境来运行——它们在 Lambda 调用过程中的特定点被调用,并提供一个事件(一个 json 对象)和一个上下文(另一个 json 对象)

您可以(并且应该!)对它们进行单元测试,就像您的语言/测试框架中的任何其他单独功能一样。

正如@Lucasz 所提到的,您应该相信,如果设置正确,API 网关和 Lambda 每次都会以相同的方式交互。一旦您运行了端到端测试并且您知道基础工作正常,任何进一步的实现都可以通过单元测试完成

有许多用于在单元测试中模拟 AWS 服务调用的库,并且对于更难以模拟的服务有很多好的实践变通方法(即:很难从另一个 lambda 内部模拟 Lambda 调用 - 但是如果您将该 lambda 调用包装在其自己的函数中,您可以模拟该函数本身以返回您想要的任何内容 - 这也是测试的好习惯!)

使用 jest,在编码单元测试中,您可以调用 lambda 处理程序,为其提供存根或模拟事件 json,以及上下文 json(可能只是空白,因为您没有使用它),然后 lambda 处理程序将执行就像您编写的任何其他具有两个参数的函数一样,包括返回您希望它返回的内容。

【讨论】:

Lambda handlers are just functions. They do not need any special environment to function 这并不完全正确。它们是容器,并且可以指定环境变量以传递给它们,例如。它们还可以依赖于eventcontext 对象,这在本地进行模拟并非易事。 Lambdas 是容器。 Lambda 处理程序只是函数。 Event 和 Context 只是 JSON 对象 - 由于您自己编写 lambda,因此您需要从它们中得到什么并不神秘。您不必复制整个上下文对象来仅运行处理程序;您只需要其中的密钥或您在处理程序中使用的事件。同样, env 只是 env 变量。任何语言都有访问它们的方法(python 中的 os.environ)——总的来说,很容易运行 handler 以查看它在单元测试和适当的模拟时是否按预期运行。 当然,我只是说 lambda 处理程序确实依赖于它们的环境,您需要小心以正确的方式复制它。例如,您不能简单地对 lambda 角色进行单元测试,以查看它是否具有执行所需操作所需的权限。上下文对象也有方法,它不是 json。 我听到了 - 重要的是要记住,单元测试并不是最终目的,而是全面测试策略的一个步骤/层。例如,它们不会用于测试权限(尽管如果您使用 CDK 并且对 cloudformation 模板结构足够熟悉,您可以在那里对其进行单元测试) - 但这些更改通常只是开始工作的几个部署- 我从 OP 的帖子中得到的印象是许多小的逻辑变化,这些变化更适合裸骨 UT

以上是关于AWS CDK - 如何在本地运行 API 和 Lambda?的主要内容,如果未能解决你的问题,请参考以下文章

使用 AWS CDK 为 AWS API 网关启用 CORS

如何在 AWS CDK 的“CodeBuildAction”中指定区域?

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

如何识别 aws cdk 应用程序何时在部署状态下运行?

如何在 AWS CDK 中使用 CfnParameter 而无需在运行时填写值

AWS CDK API Gateway 启用 Cors