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

前言

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

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

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

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

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

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

Fun Local 命令格式

使用 fun local invoke -h 能够查看 fun local invoke 的帮助信息:git

$ 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 支持经过 函数名 调用,或者 服务名/函数名 的方式调用,即github

fun local invoke function
fun local invoke service/function

好比,若是要运行名为 php72 的函数,能够直接经过如下命令完成:json

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 类型的函数

对于 nodejs六、nodejs八、python2.七、python三、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 配置

  1. 建立 vscode launch.json 文件
  2. 复制日志中的 config begin 与 config end 之间的配置到 launch.json 中。
  3. 完成上面配置后,在 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 HatDebugger 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 world


RequestId: 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"
}

想要将这段事件内容传给函数,能够经过如下三种途径:

  1. 管道: echo '{"testKey": "testValue"}' | fun local invoke nodejs8
  2. 文件: 将的 json 内容写入到文件,文件名随意,好比 event.json。而后经过 -e 指定文件名:fun local invoke -e event.json nodejs8
  3. 重定向: 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 个函数,名称分别是 nodejs六、nodejs八、php7二、python2七、python三、java8。它们对应的代码目录由 template 中的 CodeUri 定义,分别位于 nodejs六、nodejs八、php7.二、python2.七、python三、java8 目录。

更多参考

  1. Fun Repo
  2. Fun specs
  3. Fun examples
  4. Fun 发布 2.0 新版本啦
  5. 函数计算工具链新成员 —— Fun Local 发布啦

做者: tanhe123
原文连接 本文为云栖社区原创内容,未经容许不得转载。 

相关文章
相关标签/搜索