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
这并不完全正确。它们是容器,并且可以指定环境变量以传递给它们,例如。它们还可以依赖于event
和context
对象,这在本地进行模拟并非易事。
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 函数中安装外部模块?