Fn项目(http://fnproject.io/)是一个采用Apache2.0许可证的容器原生Serverless平台,您可以在各个地方(任何云或本地环境)来运行。它易于使用,支持每一种编程语言,而且易于扩展,具有高性能。
Fn专注于让用户很容易上手,在短短几分钟内就能试用它,然后随着您不断熟悉,可以逐渐使用更高级的功能。
Fn在开发和运维方面有一大堆出色的功能特性:
易于使用的命令行工具,便于开发、测试和部署函数。
只依赖一个对象:Docker。
支持高性能应用的热门函数。
与Lambda代码兼容――可以导出您的Lambda代码,并在Fn上面运行。
支持许多流行语言的FDK(函数开发工具包)。
先进的Java FDK,随带JUnit测试框架。
可以用您青睐的编排工具,比如Kubernetes、Mesosphere和Docker Swarm,部署Fn。
智能负载均衡系统专为将流量传送到函数而设计。
可扩展、模块化,支持自定义附件和整合。
搭建Fn环境并开发部署Function
1Fn环境准备
基础环境配置如下:
物理机操作系统:Win10;
虚拟机软件:VirtualBox 5.2,并安装对应版本的Extension Pack;
虚机操作系统环境:Oracle Linux 7.2。
为操作方便,建议配置虚机yum环境,修改/etc/yum.repos.d/public-yum-ol7.repo文件,建议修改以下红色部分enabled=1:

Fn需要使用Docker Hub账号,请提前注册好DockerHub账号。
1、通过yum安装Docker
sudo yum install docker-engine
2、启动Docker
[root@docker ~]# service docker start
Redirecting to bin/systemctl start docker.service
3、登录Docker Hub
使用自己的Docker Hub账号登录。
[root@docker ~]# docker login
Login with your Docker ID to push and pull imagesfrom Docker Hub. If you don't have a Docker ID, head over tohttps://hub.docker.com to create one.
Username (<DOCKERHUB NAME>):
Password:
Login Succeeded
在虚机上设定FN_REGISTRY变量:
export FN_REGISTRY=<DOCKERHUB_USERNAME>
4、安装CLI Tools
Linux使用以下命令:
curl -LSs https://raw.githubusercontent.com/fnproject/cli/master/install | sh

5、启动Fn Server
出现以下信息,Fn Server启动成功:

通过docker ps,可以看到Fn Server已经启动。
[root@docker~]# docker ps
CONTAINERID IMAGE COMMAND CREATED STATUS PORTS NAMES
f58972b570ac fnproject/fnserver "./fnserver" 8 minutes ago Up 8 minutes 2375/tcp,0.0.0.0:8080->8080/tcp fnserver
2创建自己的Function
以下我们使用Java语言创建我们的Function:Fn 提供了多个语言的FDK(Fn Development Kit),包括fdk-node,fdk-java,fdk-go,fdk-Python,fdk-ruby等。通过CLI和fdk,Fn可以帮助我们简单、快速实现Function的创建。
[root@docker ~]# fn init --runtime javamyhelloworld
Creating function at: myhelloworld
Runtime: java
Function boilerplate generated.
func.yaml created.
其中,--runtime 指定使用的语言。
通过tree命令,查看生成的文件。
可以看到除生成对应的Java文件外,还帮助我们生成了JUnit test文件。

修改function及对应的yaml文件,我们把HelloFunction.java的方法从handleRequest修改为callMe,如下代码:
public class HelloFunction {
public String callMe(String input) {
String name = (input == null || input.isEmpty()) ?"world" : input;
return "Hello, " + name +" fromFnproject!";
}
}
对应的,把func.yaml中的cmd修改为callMe,如下:
name: myhelloworld
version: 0.0.1
runtime: java
cmd: com.example.fn.HelloFunction::callMe
build_image:fnproject/fn-java-fdk-build:jdk9-1.0.59
run_image: fnproject/fn-java-fdk:jdk9-1.0.59
format: http
cmd定义的是当function激活时,外部可以调用的方法,我们可以编辑它对应到我们实现的function。对应语法如下:
cmd: <fully qualified classname>::<method name>
对应的需要Junit的test文件,修改function名称及断言:
public class HelloFunctionTest {
@Rule
publicfinal FnTestingRule testing = FnTestingRule.createDefault();
@Test
publicvoid shouldReturnGreeting() {
testing.givenEvent().enqueue();
testing.thenRun(HelloFunction.class, "callMe");
FnResult result = testing.getOnlyResult();
assertEquals("Hello, world from Fnproject!",result.getBodyAsString());
}
如果不修改test文件,build会失败。也可以简化处理,删除test目录。
3创建App并部署Function
接下来我们创建一个app,并把我们的function部署到本地。
确认当前目录在myhelloworld,并执行如下命令:
fn deploy --app myapp-java --local
出现以下信息:
[root@docker myhelloworld]# fn --verbose deploy--app myapp-java --local
Deploying myhelloworld to app: myapp-java atpath: myhelloworld
Bumped to version 0.0.2
Building image myhelloworld:0.0.2
Sending build context to Docker daemon 14.34kB
Step 1/11 : FROMfnproject/fn-java-fdk-build:jdk9-1.0.59 as build-stage
--->90ef02b5e180
Step 2/11 : WORKDIR function
--->Using cache
--->c3f347186d62
……..
Successfully built 0ad99a9ac273
………..
查看部署的app及endpoint。
[root@docker ~]# fn apps l
demoapp
myapp-java
tutorials
[root@docker ~]# fn routes list myapp-java
path image endpoint
/myhelloworld myhelloworld:0.0.2 localhost:8080/r/myapp-java/myhelloworld
4调用部署的Function
通过Fn call调用:
[root@docker ~]# echo -n "Jeff" | fncall myapp-java myhelloworld
Hello, Jeff from Fnproject![root@docker ~]#
通过cURL调用:
[root@docker ~]# curl -d "Jeff"http://localhost:8080/r/myapp-java/myhelloworld
Hello, Jeff from Fnproject![root@docker ~]#
5使用Fn UI
Fn还提供了UI,我们可以安装和启动UI,进一步简化我们的操作。
[root@docker ~]# docker run --rm -it --linkfnserver:api -p 4000:4000 -e "FN_API_URL=http://api:8080"fnproject/ui
> FunctionsUI@0.0.26 start app
> node server
WARNING: NODE_ENV value of 'production' did matchany deployment config file names.
WARNING: Seehttps://github.com/lorenwest/node-config/wiki/Strict-Mode
info: Using API url: api:8080
info: Server running on port 4000
在firefox浏览器输入http://localhost:4000,出现以下界面:

点击myapp-java,点击”Run Function”,在Payload中输入需要的字符,点击Run,执行结果如下:

拷贝cURL执行,如下:
注意:修改api:8080为localhost:8080
[root@docker~]# curl -X POST -d 'Jeff' http://localhost:8080/r/myapp-java/myhelloworld
Hello,Jeff from Fnproject![root@docker ~]#
6Function对应的Docker Container及Image
查看Docker Container:

查看Docker Images:

我们使用Java创建的第一个Function已经成功完成所有开发部署和测试!
总结

更多信息及功能请参考:http://fnproject.io及https://github.com/fnproject/fn

作者简介
王军丰,甲骨文云平台PaaS高级咨询顾问,专注于甲骨文PaaS相关产品及解决方案,具有18+年中间件技术、方案和项目实施经验。熟悉金融行业。您可以通过junfeng.wang@oracle.com与他联系。
了解更多,敬请关注甲骨文开发者社区......






