开发函数计算的正确姿势——使用FunLocal本地运行与调试

云计算 前言

首先介绍下在本文出现的几个比较重要的概念:

武都网站制作公司哪家好,找创新互联建站!从网页设计、网站建设、微信开发、APP开发、响应式网站设计等网站项目制作,到程序开发,运营维护。创新互联建站从2013年创立到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联建站

函数计算(Function Compute) : 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。函数计算更多信息 参考 。

Fun : Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API 网关、日志服务等资源。它通过一个资源配置文件(template.yml),协助您进行开发、构建、部署操作。Fun 的更多文档 参考 。

2.0 版本的 Fun,在部署这一块做了很多努力,并提供了比较完善的功能,能够做到将云资源方便、平滑地部署到云端。但该版本,在本地开发上的体验,还有较多的工作要做。于是,我们决定推出 Fun Local 弥补这一处短板。

Fun Local : Fun Local 作为 Fun 的一个子命令存在,只要 Fun 的版本大于等于 2.6.0,即可以直接通过 fun local 命令使用。Fun Local 工具可以将函数计算中的函数在本地完全模拟运行,并提供单步调试的功能,旨在弥补函数计算相对于传统应用开发体验上的短板,并为用户提供一种解决函数计算问题排查的新途径。

《开发函数计算的正确姿势》系列除本篇是为用户介绍 fun local 的使用方法外,其他几篇都会向用户展示 Fun Local 对于函数计算开发所带来的效率上的巨大提升。

Fun Local 命令格式

使用 fun local invoke -h 可以查看 fun local invoke 的帮助信息:

$funlocalinvoke-h
Usage:invoke[options]<[service/]function>
Runyourserverlessapplicationlocallyforquickdevelopment&testing.
Options:-d,--debug-portusedforlocaldebugging
-c,--configprintoutidedebugconfiguration.OptionsareVSCode-e,--eventeventfilecontainingeventdatapassedtothefunction
-h,--helpoutputusageinformation
本地运行函数

运行函数的命令格式为:

funlocalinvoke[options]<[service/]function>

其中 options、service 都是可以省略的。
从调用方式上,可以理解为,fun local invoke 支持通过 函数名 调用,或者 服务名/函数名 的方式调用,即

funlocalinvokefunctionfunlocalinvokeservice/function

比如,如果要运行名为 php72 的函数,可以直接通过以下命令完成:

funlocalinvokephp72

调用结果为:

再比如,要运行名为 nodejs8 的函数,可以使用:

funlocalinvokenodejs8

会得到如下结果:

如果 template.yml 中包含多个服务,而多个服务中包含相同名称的函数时,通过函数名的方式调用 fun 只会 运行第一个名称匹配的函数 。

如果想要精准匹配,可以使用 服务名/函数名 的方式。

比如想要调用 localdemo 下的 php72,可以使用:

funlocalinvokelocaldemo/php72

在本例中,会得到和 fun local invoke php72 一致的结果。

以下是一个运行 nodejs8 函数的演示:

本地运行 java 类型的函数

java 不同于解释型的语言,在作为函数运行前,需要先编译。在我们的例子中,可以进入到 demo 中的 java8 目录,然后执行:

mvnpackage

可以看到 log:

[INFO]skipnonexistingresourceDirectory/Users/tan/code/fun/examples/local/java8/src/test/resources
[INFO]
[INFO]---maven-compiler-plugin:3.1:testCompile(default-testCompile)@demo---
[INFO]Nosourcestocompile
[INFO]
[INFO]---maven-surefire-plugin:2.12.4:test(default-test)@demo---
[INFO]Noteststorun.
[INFO]
[INFO]---maven-dependency-plugin:2.8:copy-dependencies(copy-dependencies)@demo---
[INFO]fc-java-core-1.0.0.jaralreadyexistsindestination.
[INFO]
[INFO]---maven-jar-plugin:2.4:jar(default-jar)@demo---
[INFO]------------------------------------------------------------------------
[INFO]BUILDSUCCESS
[INFO]------------------------------------------------------------------------
[INFO]Totaltime:1.223s
[INFO]Finishedat:2018-11-22T10:45:14+08:00[INFO]FinalMemory:15M/309M
[INFO]------------------------------------------------------------------------

该命令会在 java8/target 目录下生成 demo-1.0-SNAPSHOT.jar 文件。

由于我们在 template.yml 中配置的 CodeUri 为 java8/target/demo-1.0-SNAPSHOT.jar,因此不需要任何改动,可以直接通过以下命令运行:

funlocalinvokejava8

运行结果如下:

以下是一个运行 java8 函数的演示:

本地调试

fun local invoke 支持 -d, --debug-port 选项,可以对函数进行本地单步调试。本文档只介绍如何配置调试,并不涉及调试技巧,更多文章,请 参考 。

备注:Fun Local 涉及到的 debugging 技术全部都基于各个语言通用的调试协议实现的,因此无论什么语言的开发者,即使不喜欢用 VSCode,只要使用对应语言的 remote debugging 方法都可以进行调试。

本地调试 nodejs、python 类型的函数

对于 nodejs6、nodejs8、python2.7、python3、java8 类型的函数,调试方法基本一致。下面拿 nodejs8 举例。

我们上面演示了可以通过 fun local invoke nodejs8 来运行名称为 nodejs8 的函数,如果想对该函数进行调试,只需要使用 -d 参数,并配置相应的端口号即可。

比如我们以调试方式运行函数,并将调试端口设定在 3000,可以通过下面的命令:

funlocalinvoke-d3000nodejs8

另外,推荐添加 --config 参数,在调试的同时,可以输出用来调试的 IDE 的配置信息:

funlocalinvoke-d3000--configVSCodenodejs8

命令执行结果如下:

skippullingimages...
youcanpastetheseconfigto.vscode/launch.json,andthenattachtoyourrunningfunction
/////////////////configbegin/////////////////{"version":"0.2.0","configurations":[
{"name":"fc/localdemo/nodejs8","type":"node","request":"attach","address":"localhost","port":3000,"localRoot":"/Users/tan/code/fun/examples/local/nodejs8","remoteRoot":"/code","protocol":"inspect","stopOnEntry":false
}
]
}
/////////////////configend/////////////////Debuggerlisteningonws://0.0.0.0:3000/b65c288b-bd6a-4791-849b-b03e0d16b0ce
Forhelpseehttps://nodejs.org/en/docs/inspector

程序会阻塞在这里,并不会继续往下执行。只有 IDE 的连接上来后,程序才会继续执行。接下来,我们针对 VSCode 配置、VSCode 调试两个方面分别进行讲解。

其中 VSCode 配置只有在第一次对函数进行调试时才需要,如果已经配置过,则不需要再次配置。

VSCode 配置

创建 vscode launch.json 文件

复制日志中的 config begin 与 config end 之间的配置到 launch.json 中。

完成上面配置后,在 Debug 视图可以看到配置的函数列表。

至此,VSCode 配置完成。VSCode 更多配置知识可以参考 官方文档 。

VSCode 调试

VSCode 配置成功后,只需要在 VSCode 编辑器侧边栏单击设置断点,然后点击“开始调试”按钮,即可开始调试。

以下是一个 nodejs8 函数本地单步调试的流程例子:

本地调试 java 类型的函数

调试 java 函数的过程和 nodejs、python 是类似的。但由于 java 程序员通常喜欢用 IDEA、Eclipse 这样的 IDE,所以我们单独拿出来说一下。

使用 VSCode 调试 java

使用 VSCode 调试 java 时,需要安装两个插件: Language Support for Java(TM) by Red Hat Debugger for Java 。利用 VSCode 的插件市场安装插件很简单,可以 参考 。

以下是一个使用 VSCode 调试 java 类型函数的例子:

使用 IDEA 调试 java IDEA 配置

IDEA 配置 remote debugging 还是比较简单的,首先在菜单栏依次点击 Run -> Edit Configurations...

然后新建一个 Remote Debugging:

然后我们随意输出一个名字,并配置端口号为 3000.

以下是一个配置 IDEA remote debugging 的完整流程演示:

使用 IDEA 开始调试

首先将 java 函数以 debug 的方式运行起来:

funlocalinvoke-d3000java8

可以看到函数卡在这里了,接着我们使用 IDEA 连接并开始调试。可以通过菜单栏上的 Run -> Debug... 或者工具栏直接点击 Debug 按钮,即可开始调试。

以下是一个用 IDEA 进行 remote debugging 的完整流程演示:

本地调试 php 类型的函数

php 的调试与其他类型的函数调试在流程上有一些不同。

首先,php 的运行通过 fun local invoke php72 命令完成,这与其他类型的函数一致。调试时,也像其他类型的函数一样,通过 -d 参数以调试模式启动函数:

funlocalinvoke-d3000--configVSCodephp72

但不同的是,以 debug 方式运行 php 函数后,php 函数并没有阻塞等待 vscode 调试器的连接,而是直接运行结束。

skippullingimages...
youcanpastetheseconfigto.vscode/launch.json,andthenattachtoyourrunningfunction
/////////////////configbegin/////////////////{"version":"0.2.0","configurations":[
{"name":"fc/localdemo/php72","type":"php","request":"launch","port":3000,"stopOnEntry":false,"pathMappings":{"/code":"/Users/tan/code/fun/examples/local/php7.2"
},"ignore":["/var/fc/runtime/**"
]
}
]
}
/////////////////configend/////////////////FunctionComputephp7.2runtimeinited.
FCInvokeStartRequestId:6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4
FCInvokeEndRequestId:6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4
helloworldRequestId:6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4BilledDuration:48msMemorySize:1998MBMaxMemoryUsed:58MB

这是因为,对于 php 程序,需要首先启动 vscode 的调试器。

php 类型的函数启动 VSCode 调试器的流程与其他类型的函数一致:复制上面日志中的 vscode 配置到 launch.json,单击“开始调试”即可。

然后在终端重新以调试模式启动 php 函数即可开始调试:

funlocalinvoke-d3000php72

Event 事件源

函数计算提供了丰富的触发器,包括但不局限于对象存储触发器、日志服务触发器、CDN 事件触发器等。在本地无论是运行还是调试函数时,为了能够完全模拟线上环境,通常需要构造触发事件。

触发事件可以是一段可读的 json 配置,也可以是一段非可读的二进制数据。这里我们拿 json 举例,假设触发事件内容为:

{"testKey":"testValue"}

想要将这段事件内容传给函数,可以通过以下三种途径:

管道: echo '{"testKey": "testValue"}' | fun local invoke nodejs8

文件: 将的 json 内容写入到文件,文件名随意,比如 event.json。然后通过 -e 指定文件名: fun local invoke -e event.json nodejs8

重定向: fun local invoke nodejs8 < event.json 或者 fun local invoke nodejs8 <<< '{"testKey": "testValue"}' 等等。更多信息可以参考这篇 文章 。

环境变量

在 template.yml 中配置的 EnvironmentVariables 会与线上行为一致,当函数运行时,可以通过代码获取到。更多信息 参考 。

在本地运行函数时,除了 EnvironmentVariables 配置的环境变量,fun 还会额外提供一个 local=true 的环境变量,用来标识这是一个本地运行的函数。

通过这个环境变量,用户可以区分是本地运行还是线上运行,以便于进行一些特定的逻辑处理。

Initializer

在 template.yml 中配置的 Initializer 属性会与线上行为一致,当函数运行时,会首先运行 Initializer 指定的方法。Initializer 更多信息 参考 。

Credentials

用户可以通过 Credentials 中存储的 ak 信息访问阿里云的其他服务。Fun local 在本地运行函数时,会按照与 fun deploy 相同的 策略 寻找 ak 信息。

关于函数计算 Credentials 的描述,可以 参考 。

以下是一个根据本地、线上环境的不同,利用函数提供的 Credentials 配置 oss client 的例子:

local=bool(os.getenv('local',""))if(local):print'thankyouforrunningfunctioninlocal!!!!!!'
auth=oss2.Auth(creds.access_key_id,
creds.access_key_secret)else:
auth=oss2.StsAuth(creds.access_key_id,
creds.access_key_secret,
creds.security_token)
附录 代码

本文讲解涉及到的 demo 代码,托管在 github 上。项目目录结构如下:

.
├──java8│├──pom.xml│├──src││└──main││└──java││└──example││└──App.java│└──target│└──demo-1.0-SNAPSHOT.jar├──nodejs6│└──index.js├──nodejs8│└──index.js├──php7.2│└──index.php├──python2.7│└──index.py├──python3│└──index.py└──template.yml

template.yml 定义了函数计算模型,其中定义了一个名为 localdemo 的服务,并在该服务下,定义了 6 个函数,名称分别是 nodejs6、nodejs8、php72、python27、python3、java8。它们对应的代码目录由 template 中的 CodeUri 定义,分别位于 nodejs6、nodejs8、php7.2、python2.7、python3、java8 目录。

更多参考

Fun Repo

Fun specs

Fun examples

Fun 发布 2.0 新版本啦

函数计算工具链新成员 —— Fun Local 发布啦


分享文章:开发函数计算的正确姿势——使用FunLocal本地运行与调试
URL标题:http://myzitong.com/article/chogsd.html