开发函数计算的正确姿势——使用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-port本地运行函数usedforlocaldebugging -c,--config printoutidedebugconfiguration.OptionsareVSCode-e,--event eventfilecontainingeventdatapassedtothefunction -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-d3000php72Event 事件源
函数计算提供了丰富的触发器,包括但不局限于对象存储触发器、日志服务触发器、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本地运行与调试
当前路径:http://azwzsj.com/article/chogsd.html