写点什么

Serverless 架构下如何对应用进行调试

作者:刘宇
  • 2021 年 12 月 15 日
  • 本文字数:4989 字

    阅读完需:约 16 分钟

Serverless架构下如何对应用进行调试

在应用开发过程中,或者应用开发完成,当所执行结果不符合预期时,通常要进行一定的调试工作。但是在 Serverless 加架构下,调试往往会受到极大的环境因素限制,通常情况下会出现的情况是,所开发的应用在本地是可以比较健康的、符合预期的运行,但是在 FaaS 平台上,则会出现一些不可预测的问题;或者是在一些特殊的环境下,本地没有办法模拟线上环境,难以进行项目的开发和调试。


Serverless 应用的调试,一直都是备受诟病的,但是各个云厂商并没有因此放弃在调试方向的不断深入探索。以阿里云函数计算为例,其提供了在线调试、本地调试等多种调试方案。

在线调试

简单调试

所谓的简单地调试,就是在控制台来进行调试,以阿里云函数计算为例,可以在控制台通过执行按钮,进行基本的调试:



必要时候,也可以通过设置 Event 来模拟一些事件:



在线进行调试的好处是,可以使用线上的一些环境进行代码的测试。否则当线上环境拥有 VPC 等资源时,在本地环境是很难进行调试,例如数据库需要通过 VPC 来进行访问时,或者有对象存储触发器的业务逻辑等。

远程调试

端云联调本地除了一个通道服务容器,仍有一个函数计算容器,用来执行本地函数,远程的辅助函数只是单纯将远程流量发送到本地;但是在实际调试过程中,为了更加简单方便,还需要登录到实例中进行项目调试,此时可以选择使用远程调试功能进行调试,相对以端云联调,远程调试本地只有一个通道服务容器,执行过程全部依赖于线上,远程函数将执行结果返回;其整体架构简图如图 5.22 所示:



在远程调试中,用户通过 remote setup 指令搭建本地与远程的容器通道,并在远程新建一个与本地配置完全相同的函数。之后,通过通道服务,用户可以直接获取线上的 VPC 内网资源,比如 NAS,OSS 等等。用户还可以通过容器直接进入远程的函数计算环境,进行更加细致地调试。使用远程调试组件启动单步调试,用户只需在 remote setup 后,启动 IDE 的调试模式(当前仅支持 VSCode,Intellij)。使用 remote invoke 启动函数,此时即可发现程序运行到断点处。远程调试提供了登陆功能。在完成 s remote setup 后,可以通过代理容器远程登录到函数计算实例。通过查询当前代理容器的 ID:


docker ps
复制代码


然后可以进入容器实例:


docker exec -it ${CONTAINER_ID} bash
复制代码


直接登录远程实例即可(即线上的真实环境实例):


ssh root@${IP} -p ${PORT}
复制代码


完整的操作流程如下图所示:


最佳实践案例

三步完成端云联调


远程调试可以通过三个非常简单的步骤快速实现:


  • 步骤 1: 在已有的项目下,创建远程调试的辅助资源,开启远程调试模式:s remote setup

  • 步骤 2: 在完成远程调试模式开启动作之后,通过s remote invoke或者线上的事件进行函数的触发,调试;

  • 步骤 3: 完成远程调试之后,通过s remote clean命令,对对因远程调试而产生的辅助资源进行清理;


断点调试


通过与常见的 IDE 进行结合,可以在常见的 IDE 上实现远程调试的断点调试。


VSCode 断点调试案例


  • 步骤 1: 在已有的项目下,开启调试模式的远程调试能力:$ s remote setup --config vscode --debug-port 3000,命令执行完成功后, 本地的函数计算执行环境会阻塞等待调用(执行环境本质是一个 HTTP Server);

  • 此时若要进行断点调试,需要进行以下的操作在 VSCode 上进行相关的配置:Serverless Devs 开发者工具自动在工程目录下面生成 .vscode/launch.json 文件, 通过下图完成调试配置:


  • 步骤 2: 打开一个新的终端,通过remote invoke进行触发(例如s remote invoke),回到 VSCode 界面,既可以进行断点调试了:


  • 调试完成后返回结果。

  • 若要在调用的时候制定传入的 event 参数,可以使用 --event,例如s remote invoke -h

  • 步骤 3: 完成远程调试之后,通过s remote clean命令,对对因远程调试而产生的辅助资源进行清理;


Intelli 断点调试案例


  • 步骤 1: 例如需要在 IDEA 下进行调试,可以在已有的项目下,开启调试模式的远程调试能力:$ s remote setup --config idea --debug-port 3000,命令执行完成功后, 本地的函数计算执行环境会阻塞等待调用(执行环境本质是一个 HTTP Server);

  • 此时若要进行断点调试,需要进行以下的操作在 IDEA 上进行相关的配置:

  • 在菜单栏选择 Run… > Edit Configurations 。

  • 新建一个 Remote Debugging 。

  • 自定义调试器名称,并将端口配置为 3000 。

  • 上述配置完成后,在 IDEA 编辑器侧边栏为函数代码增加断点,点击"开始调试"按钮。

  • 步骤 2: 打开一个新的终端,通过remote invoke进行触发(例如s remote invoke),回到 IDEA 界面,既可以进行断点调试了:


  • 调试完成后返回结果。

  • 若要在调用的时候制定传入的 event 参数,可以使用 --event,例如s remote invoke -h

  • 步骤 3: 完成远程调试之后,通过s remote clean命令,对对因远程调试而产生的辅助资源进行清理;

端云联调

所谓的端云联调指的是在本地进行 Serverless 应用开发时,往往会涉及到一些线上资源,例如通过对象存储触发器触发函数执行,通过 VPC 访问数据库等,此时由于线上线下环境的不一致性,会让线下的开发、调试面临极大的挑战。Serverless Devs 团队通过搭建 Proxy 辅助函数的方法,将线上线下资源打通,可以快速帮助开发者在本地进行函数的开发与调试。



如图所示, Serverless Devs 开发者工具会根据开发者的函数的 yaml 文件配置,创建辅助服务和辅助函数(这个辅助服务和函数的配置跟您的服务和函数是相同的),并通过辅助服务和辅助函数实现线上线下的网络环境打通,以及完整的端云联调能力:


  1. 调用这个辅助函数, 流量会打回到本地的调试实例, 这个时候本地实例接受到 event 和 context 是真实来自线上的

  2. 本地调试的实例运行函数逻辑, 能直接利用辅助函数运行的那个容器, 可以直接访问 vpc 内网以及一些云服务的内网地址


具体的使用流程是:


  1. 执行 s proxied setup 来准备端云联调所需的辅助资源以及本地环境;

  2. 对于无触发器的普通事件函数或者 http 触发器函数,准备工作完成后,启动另一个新的终端,切换到该项目路径下,执行 s proxied invoke 来调用本地函数;

  3. 完成调试任务之后,可以执行 s proxied cleanup 清理端云联调所需的辅助资源以及本地环境;


除了通过命令行使用端云联调能力,也可以在 VSCode 等开发者工具中使用,例如:


最佳实践案例

三步完成端云联调


端云联调可以通过三个非常简单的步骤快速实现:


  • 步骤 1: 在已有的项目下,创建端云联调的辅助资源,开启端云联调模式:s proxied setup

  • 步骤 2: 在完成端云联调模式开启动作之后,通过s proxied invoke或者线上的事件进行函数的触发,调试;

  • 步骤 3: 完成端云联调之后,通过s proxied clean命令,对对因端云联调而产生的辅助资源进行清理;


断点调试


通过与常见的 IDE 进行结合,可以在常见的 IDE 上实现端云联调的断点调试。


VSCode 断点调试案例


  • 步骤 1: 在已有的项目下,开启调试模式的端云联调能力:$ s proxied setup --config vscode --debug-port 3000,命令执行完成功后, 本地的函数计算执行环境会阻塞等待调用(执行环境本质是一个 HTTP Server);

  • 此时若要进行断点调试,需要进行以下的操作在 VSCode 上进行相关的配置:Serverless Devs 开发者工具自动在工程目录下面生成 .vscode/launch.json 文件, 通过下图完成调试配置:


  • 步骤 2: 打开一个新的终端,通过proxied invoke进行触发(例如s proxied invoke,如果是事件函数也可以通过线上触发器进行触发,此时要注意将触发器临时指向辅助函数,详情参考proxied invoke 命令操作过程),回到 VSCode 界面,既可以进行断点调试了:


  • 调试完成后返回结果。

  • 若要在调用的时候制定传入的 event 参数,可以使用 --event,例如s proxied invoke -h

  • 步骤 3: 完成端云联调之后,通过s proxied clean命令,对对因端云联调而产生的辅助资源进行清理;


Intelli 断点调试案例


  • 步骤 1: 例如需要在 IDEA 下进行调试,可以在已有的项目下,开启调试模式的端云联调能力:$ s proxied setup --config intellij --debug-port 3000,命令执行完成功后, 本地的函数计算执行环境会阻塞等待调用(执行环境本质是一个 HTTP Server);

  • 此时若要进行断点调试,需要进行以下的操作在 IDEA 上进行相关的配置:

  • 在菜单栏选择 Run… > Edit Configurations 。

  • 新建一个 Remote Debugging 。

  • 自定义调试器名称,并将端口配置为 3000 。

  • 上述配置完成后,在 IDEA 编辑器侧边栏为函数代码增加断点,点击"开始调试"按钮。

  • 步骤 2: 打开一个新的终端,通过proxied invoke进行触发(例如s proxied invoke,如果是事件函数也可以通过线上触发器进行触发,此时要注意将触发器临时指向辅助函数,详情参考proxied invoke 命令操作过程),回到 IDEA 界面,既可以进行断点调试了:


  • 调试完成后返回结果。

  • 若要在调用的时候制定传入的 event 参数,可以使用 --event,例如s proxied invoke -h

  • 步骤 3: 完成端云联调之后,通过s proxied clean命令,对对因端云联调而产生的辅助资源进行清理;

本地调试

命令行工具

就目前来看,大部分 FaaS 平台都会为用户提供相对完备的命令行工具,包括 AWS 的 SAM CLI,阿里云的 Funcraft,同时也有一些开源项目例如 Serverless Framework、Serverless Devs 等对多云厂商的支持等。通过命令行工具进行代码调试的方法很简单,以 Serverless Devs 为例,本地调试阿里云函数计算:


首先确保,本地拥有一个函数计算的项目,然后在项目下执行调试指令,例如在 Docker 中进行调试:



图 1.70: 通过命令行进行本地调试

编辑器插件

以 VScode 插件为例,当下载好阿里云函数计算的 VSCode 插件,并且配置好账号信息之后,可以在本地新建函数,并且在进行打点,之后可以进行断点调试:



图 1.71: 编辑器插件中进行调试


当函数调试完成之后,可以进行部署等操作。

其他调试方案

Web 框架的本地调试

在阿里云 FaaS 平台开发传统 Web 框架,以 Python 语言 Bottle 框架为例,可以增加:


app = bottle.default_app()
复制代码


并且对 run()方法进行条件限制(if __name__ == '__main__')


if __name__ == '__main__':    bottle.run(host='localhost', port=8080, debug=True)例如:# index.pyimport bottle
@bottle.route('/hello/<name>')def index(name): return "Hello world"
app = bottle.default_app()
if __name__ == '__main__': bottle.run(host='localhost', port=8080, debug=True)
复制代码


这样,可以在本地开发的同时,和传统开发思路一样,在本地进行调试。当部署到线上时,只需要在入口方法处填写index.app,即可实现平滑的部署。

本地模拟事件调试

针对非 Web 框架,可以在本地构建一个方法,例如要调试一下对象存储触发器,可以是:


import json
def handler(event, context): print(event)
def test(): event = { "events": [ { "eventName": "ObjectCreated:PutObject", "eventSource": "acs:oss", "eventTime": "2017-04-21T12:46:37.000Z", "eventVersion": "1.0", "oss": { "bucket": { "arn": "acs:oss:cn-shanghai:123456789:bucketname", "name": "testbucket", "ownerIdentity": "123456789", "virtualBucket": "" }, "object": { "deltaSize": 122539, "eTag": "688A7BF4F233DC9C88A80BF985AB7329", "key": "image/a.jpg", "size": 122539 }, "ossSchemaVersion": "1.0", "ruleId": "9adac8e253828f4f7c0466d941fa3db81161****" }, "region": "cn-shanghai", "requestParameters": { "sourceIPAddress": "140.205.***.***" }, "responseElements": { "requestId": "58F9FF2D3DF792092E12044C" }, "userIdentity": { "principalId": "123456789" } } ] } handler(json.dumps(event), None) if __name__ == "__main__": print(test())
复制代码


这样通过构造一个 event 对象,即可实现模拟事件触发。

发布于: 4 小时前阅读数: 5
用户头像

刘宇

关注

阿里云Serverless云布道师 2020.01.04 加入

阿里云Serverless产品经理,国防科大在读博士,《Serverless架构》、《Serverless实践》、《人人都能学会的Serverless架构》等书籍作者,Serverless Devs发起人,Anycodes在线编程负责人。

评论

发布
暂无评论
Serverless架构下如何对应用进行调试