云计算
前言
首先介绍下在本文出现的几个比较重要的概念:
函数计算(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 的帮助信息:
$ fun local invoke -h Usage: invoke [options] <[service/]function> Run your serverless application locally for quick development & testing. Options: -d, --debug-port <port> used for local debugging -c, --config <ide> print out ide debug configuration. Options are VSCode -e, --event <path> event file containing event data passed to the function -h, --help output usage information
本地运行函数
运行函数的命令格式为:
fun local invoke [options] <[service/]function>
其中 options、service 都是可以省略的。
从调用方式上,可以理解为,fun local invoke 支持通过
函数名
调用,或者
服务名/函数名
的方式调用,即
fun local invoke functionfun local invoke service/function
比如,如果要运行名为 php72 的函数,可以直接通过以下命令完成:
fun local invoke php72
调用结果为:
再比如,要运行名为 nodejs8 的函数,可以使用:
fun local invoke nodejs8
会得到如下结果:
如果 template.yml 中包含多个服务,而多个服务中包含相同名称的函数时,通过函数名的方式调用 fun 只会
运行第一个名称匹配的函数
。
如果想要精准匹配,可以使用
服务名/函数名
的方式。
比如想要调用 localdemo 下的 php72,可以使用:
fun local invoke localdemo/php72
在本例中,会得到和
fun local invoke php72
一致的结果。
以下是一个运行 nodejs8 函数的演示:
本地运行 java 类型的函数
java 不同于解释型的语言,在作为函数运行前,需要先编译。在我们的例子中,可以进入到 demo 中的 java8 目录,然后执行:
mvn package
可以看到 log:
[INFO] skip non existing resourceDirectory /Users/tan/code/fun/examples/local/java8/src/test/resources [INFO] [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ demo --- [INFO] No sources to compile [INFO] [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ demo --- [INFO] No tests to run. [INFO] [INFO] --- maven-dependency-plugin:2.8:copy-dependencies (copy-dependencies) @ demo --- [INFO] fc-java-core-1.0.0.jar already exists in destination. [INFO] [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ demo --- [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 1.223 s [INFO] Finished at: 2018-11-22T10:45:14+08:00[INFO] Final Memory: 15M/309M [INFO] ------------------------------------------------------------------------
该命令会在 java8/target 目录下生成 demo-1.0-SNAPSHOT.jar 文件。
由于我们在 template.yml 中配置的 CodeUri 为 java8/target/demo-1.0-SNAPSHOT.jar,因此不需要任何改动,可以直接通过以下命令运行:
fun local invoke java8
运行结果如下:
以下是一个运行 java8 函数的演示:
本地调试
fun local invoke 支持
-d, --debug-port <port>
选项,可以对函数进行本地单步调试。本文档只介绍如何配置调试,并不涉及调试技巧,更多文章,请
参考
。
备注:Fun Local 涉及到的 debugging 技术全部都基于各个语言通用的调试协议实现的,因此无论什么语言的开发者,即使不喜欢用 VSCode,只要使用对应语言的 remote debugging 方法都可以进行调试。
本地调试 nodejs、python 类型的函数
对于 nodejs6、nodejs8、python2.7、python3、java8 类型的函数,调试方法基本一致。下面拿 nodejs8 举例。
我们上面演示了可以通过
fun local invoke nodejs8
来运行名称为 nodejs8 的函数,如果想对该函数进行调试,只需要使用 -d 参数,并配置相应的端口号即可。
比如我们以调试方式运行函数,并将调试端口设定在 3000,可以通过下面的命令:
fun local invoke -d 3000 nodejs8
另外,推荐添加 –config 参数,在调试的同时,可以输出用来调试的 IDE 的配置信息:
fun local invoke -d 3000 --config VSCode nodejs8
命令执行结果如下:
skip pulling images ... you can paste these config to .vscode/launch.json, and then attach to your running function ///////////////// config begin /////////////////{ "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 } ] } ///////////////// config end /////////////////Debugger listening on ws://0.0.0.0:3000/b65c288b-bd6a-4791-849b-b03e0d16b0ce For help see https://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 的方式运行起来:
fun local invoke -d 3000 java8
可以看到函数卡在这里了,接着我们使用 IDEA 连接并开始调试。可以通过菜单栏上的
Run -> Debug...
或者工具栏直接点击 Debug 按钮,即可开始调试。
以下是一个用 IDEA 进行 remote debugging 的完整流程演示:
本地调试 php 类型的函数
php 的调试与其他类型的函数调试在流程上有一些不同。
首先,php 的运行通过
fun local invoke php72
命令完成,这与其他类型的函数一致。调试时,也像其他类型的函数一样,通过 -d 参数以调试模式启动函数:
fun local invoke -d 3000 --config VSCode php72
但不同的是,以 debug 方式运行 php 函数后,php 函数并没有阻塞等待 vscode 调试器的连接,而是直接运行结束。
skip pulling images ... you can paste these config to .vscode/launch.json, and then attach to your running function ///////////////// config begin /////////////////{ "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/**" ] } ] } ///////////////// config end /////////////////FunctionCompute php7.2 runtime inited. FC Invoke Start RequestId: 6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4 FC Invoke End RequestId: 6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4 hello worldRequestId: 6e8f7ed7-653d-4a6a-94cc-1ef0d028e4b4 Billed Duration: 48 ms Memory Size: 1998 MB Max Memory Used: 58 MB
这是因为,对于 php 程序,需要首先启动 vscode 的调试器。
php 类型的函数启动 VSCode 调试器的流程与其他类型的函数一致:复制上面日志中的 vscode 配置到 launch.json,单击“开始调试”即可。
然后在终端重新以调试模式启动 php 函数即可开始调试:
fun local invoke -d 3000 php72
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 'thank you for running function in local!!!!!!' 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 发布啦