前言
相信有很多同学公司项目都有用到 AWS 或者有同学在学习 AWS,我们知道像 AWS 这样的云服务,我们不太能很方便的去在本地开发的时候连接云上的服务,更何况 staging/production 环境还会有安全方面的考虑。那么当我们创建好一个项目的时候,我们如何去搭建其本地开发环境方便我们在本地开发调试呢?没错!使用 localstack!
LocalStack - A fully functional local AWS cloud stack
LocalStack provides an easy-to-use test/mocking framework for developing Cloud applications.
Currently, the focus is primarily on supporting the AWS cloud stack.
LocalStack 是提供给开发者一个方便去测试和 mock 服务的框架, 目前主要提供 AWS 云服务。
如何使用?
例:使用 LocalStack 创建一个 SNS服务
想像我们有这样一个 SpringBoot 服务,提供接口在用户提交一条记录的时候给用户发邮件,一般情况这种业务我们都会将保存数据库和发邮件异步执行。使用 AWS 的话,我们就可以在保存数据库之后调用 SNS 服务,发布一个 Event
然后等待下游邮件服务订阅对应的 topic 然后消费。
那么如何创建呢?如下在 docker-compose.yml
文件中加入localstack
,SERVICES 指定好 sns
:
docker-compose.yml
1 | version: "3.7" |
create-localstack-topic.sh
此外,可以看到我们还 volume 了一个脚本进去,那就是创建 SNS 的脚本。实际上这个命令就是 aws cli,在其官网就可以找得到,我们只需要把 aws
换成 awslocal
1 |
|
启动日志
当启动 docker-compose up localstack
的时候,就在该容器中创建好了 SNS 服务提供给我们使用。
1 | sns_1 | Waiting for all LocalStack services to be ready |
在命令行调用
1 | aws --endpoint-url=http://localhost:4566 sns publish --topic-arn arn:aws:sns:ap-southeast-2:000000000000:demo-events-topic --region ap-southeast-2 --message "Hello SNS" |
注意,在本地使用 aws 命令调用 localstack 中的服务的时候,需要覆盖endpoint-url
, 否则回去拿着 credentials 调用实际环境的服务。
在 SpringBoot 中使用的注意点
在 SpringBoot 或者其他代码库(如node)中使用的话,可以根据不同的环境创建不同的 SNSClient
, 本地环境的注意要覆盖 endpoint:
1 |
|
启动多个服务
上面只是一个启动 SNS 服务的例子,实际使用中,我们都会多种服务结合使用。比如会有一个 SQS 服务, 订阅了 SNS 的 topic,然后去 trigger 一个 lambda,执行相应的一些任务,那么如何在本地实现这些服务的相互订阅与触发呢?实际上只需要在一个 localstack 中启动多个服务然后执行一些脚本建立之间的关系(具体命令和 aws cli 一样)就可以了,如下:
docker-compose.yml
1 | version: "3.7" |
kms_seed.yaml
我在这里启动了 sns,sqs,kms,cloudwatch,lambda。 比较值得一说的除了在本地访问 sqs, sns, kms 等需要覆盖掉 endpoint-url
之外, 在本地使用 kms 还需要指定一个 seed.yml
来用它进行加解密。
1 | Keys: |
创建脚本 create-localstack.sh
1 | !/bin/bash |
本地启动
直接运行 docker-compose up localstack
本地执行
现在在命令行发送一条 SNS 的消息,就可以 trigger 我们的 Lambda 执行了。
1 | aws --endpoint-url=http://localhost:4566 sns publish --topic-arn arn:aws:sns:ap-southeast-2:000000000000:demo-topic --region ap-southeast-2 --message "Hello SNS - SQS - Lambda" |
在 Lambda 的 index.ts 写一个 handler()
方法:
1 | require('./overwriteAwsLocalEndpoint'); //overwrite aws local endpoint,Please keep it here. |
打印一下 SQS 的消息体。
结果如下
1 | localstack | > START RequestId: ce5ae5ff-054d-16e0-dc62-71161118d3bd Version: $LATEST |
关于 LocalStack 中 Lambda 的使用
在本地创建 Lambda 运行环境是我觉得诸多 service 中比较麻烦的一个,以下是官方对于 Lambda 的创建时候的配置详解
1 | STEPFUNCTIONS_LAMBDA_ENDPOINT: URL to use as the Lambda service endpoint in Step Functions. By default this is the LocalStack Lambda endpoint. Use default to select the original AWS Lambda endpoint. |
FAQ
- 为什么我使用 SNS、KMS 总是报一些 client 的 credentials 的错误?
- 因为没有覆盖 本地环境需要的 endpoint-url, 参考本文中的解释
- 为什么给 SNS 发消息成功了却没有触发到 Lambda?
- 请检查你的创建脚本,确保你的 SQS 订阅了 SNS 的对应 topic,SQS 有能够触发 Lambda 的 Mapping
- 本例代码库地址?
最后
如果你在使用 localstack 的时候遇到了什么问题,欢迎告诉我一起研究讨论。