新网Logo
首页>虚机资讯>

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

登录 注册

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

  • 来源:网络
  • 更新日期:2020-08-10

摘要:云计算 前言 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute) : 函数计算是一个事件驱动的服务,通过函数计

云计算 前言

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

函数计算(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 发布啦


新网虚拟主机