FAAS原理白话就是,用户提交一段函数代码(如js代码),我们后台把代码拼接为dockerfile(根据用户的函数语言,自动组装(如js代码需要js环境,nginx),后台打一个镜像,然后k8s集群根据用户的配置需求,跑这个docker镜像。用户删除函数,直接把镜像销毁。
以下为开源FAAS:Openwhisk的基本使用
Openwhisk是属于Apache基金会的开源Faas计算平台,由IBM在2016年公布并贡献给开源社区。IBM Cloud本身也提供完全托管的OpenWhisk Faas服务IBM Cloud Function。从业务逻辑来看,OpenWhisk同AWS Lambda一样,为用户提供基于事件驱动的无状态的计算模型,并直接支持多种编程语言。
OpenWhisk特点:
• 高性能,高扩展性的分布式FaaS计算平台
• 函数的代码及运行时全部在Docker容器中运行,利用Docker engine实现FaaS函数运行的管理、负载均衡、扩展.
• OpenWhisk所有其他组件(如:API网关,控制器,触发器等)也全部运行在 Docker容器中。这使得OpenWhisk全栈可以很容易的部署在任意IaaS/PaaS平台上。
• 相比其他FaaS实现(比如OpenFaaS),OpenWhisk更像是一套完整的Serverless 解决方案,除了容器的调用和函数的管理,OpenWhisk 还包括了用户身份验证/鉴权、函数异步触发等功能。
目前支持的语言: Nodejs, Python, Java, php, Ruby, Go, Rust, dotnet, Ballerina, blackBoxes。
安装
整个安装需要提前安装java跟nodejs。
• 安装java
下载JDK
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
将JDK安装包上传到服务器上并解压
$ tar -zxvf jdk-8u171-linux-x64.tar.gz
#切换到当前用户目录下面,编辑配置文件
$ cd ~
$ vim .bash_profile
在.bash_profile文件最后添加
JAVA_HOME=/home/tomcat/jdk1.8.0_171
CLASSPATH=$JAVA_HOME/lib:$JAVA_HOME/jre/lib
PATH=$PATH:$JAVA_HOME/bin:$JAVA_HOME/jre/bin
export JAVA_HOME CLASSPATH PATH
#验证
$ java -version
• 安装nodejs
下载Node.js安装包
wget https://nodejs.org/dist/v10.15.3/node-v10.15.3-linux-x64.tar.xz
#解压文件
tar xvf node-v10.15.3-linux-x64.tar.xz
创建软链接
ln -s /home/node-v10.15.3-linux-x64.tar.xz/bin/node /usr/local/bin/node
ln -s /home/node-v10.15.3-linux-x64.tar.xz/bin/npm /usr/local/bin/npm
查看node, npm版本
node -v
npm -v
如果成功,则安装完成
• 编译openwhisk
如果没有代码,可以从本地上传或从git clone下载
yum install git
git clone下来
git clone https://github.com/apache/incubator-openwhisk.git openwhisk
切换到openwhisk目录,运行下面命令
$ ./gradlew :core:standalone:build
• 配置OpenWhisk Cli工具:下载https://github.com/apache/openwhisk-cli
上传到服务器解压, 解压
设置API HOST
wsk property set --apihost http://172.17.0.1:3233
设置auth
wsk property set --auth 789c46b1-71f6-4ed5-8c54-816aa4f8c502
可以通过以下命令获取当前的auth
wsk property get --auth
• 在.\bin目录下面会有相应的可执行文件。
java -jar openwhisk-standalone.jar
会有如下输出:
____ ___ _ _ _ _ _
/\ \ / _ \ _ __ ___ _ __ | | | | |__ (_)___| | __
/\ /__\ \ | | | | '_ \ / _ \ '_ \| | | | '_ \| / __| |/ /
/ \____ \ / | |_| | |_) | __/ | | | |/\| | | | | \__ \ <
\ \ / \/ \___/| .__/ \___|_| |_|__/\__|_| |_|_|___/_|\_\
\___\/ tm |_|
Running pre flight checks ...
Local Host Name: 172.17.0.1
Local Internal Name: 172.17.0.1
[ OK ] 'docker' cli found. (Docker version 19.03.6, build 369ce74a3c)
[ OK ] 'docker' version 19.3.6 is newer than minimum supported 18.3.0
[ OK ] 'docker' is running.
[ OK ] 'wsk' cli found. (2019-09-23T17:46:38.323+0000)
[ WARN ] Configure wsk via below command to connect to this server as [guest]
wsk property set --apihost 'http://172.17.0.1:3233' --auth '23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP'
[ OK ] Server port [3233] is free
服务起来后设置提示的命令:设置apihost和auth
wsk property set --apihost 'http://172.17.0.1:3233' --auth '23bc46b1-71f6-4ed5-8c54-816aa4f8c502:123zO3xZCLrMN6v2BKK1dXYFpXlPkccOFqm12CdAsMgRU4VrNZ9lyGVCGuMDGIwP'
• 运行Hello world
创建hello.js文件
/**
* Hello world as an OpenWhisk action.
*/
function main(params) {
var name = params.name || 'World';
return {payload: 'Hello, ' + name + '!'};
}
创建action
$ wsk action create hellotest hello.js
ok: created action hellotest
$ wsk action invoke hellotest --result
{
"playload": "hello world"
}
系统流程
先介绍一下 OpenWhisk 中从事件触发到函数执行完毕的流程。 OpenWhisk 中,代码是基于事件(Event)触发的。事件产生于事件源(feed),可以用于触发函数的事件多种多样:可以是IoT设备传感器发出的信号,可以是一个 Github repo的push,也可以是最简单的一个前端HTTP 请求。事件与对应的函数代码,通过规则(Rule)绑定。通过匹配事件对应的规则,OpenWhisk会触发对应的行为(Action)。值得注意的是,多个Action 可以串联,完成复杂的操作。
整体架构
参考链接:https://github.com/apache/openwhisk/blob/master/docs/about.md
- 面向用户的REST API(Nginx): OpenWhisk 的核心系统通过Rest API 接收函数触发和函数的CRUD请求。如一个函数触发的POST请求格式如下···POST /api/v1/namespaces/$userNamespace/actions/myAction ···此处的nginx 服务器主要用于接收 HTTPS 请求(SSL termination),并将处理后的 HTTP 请求直接转发给控制器(Controller).
- 控制器(Controller, 真正进入系统): 真正开始处理请求的地方。控制器是用 Scala 语言实现的,并提供了对应的 REST API,接收 Nginx 转发的请求。Controller 分析请求内容,进行下一步处理。
- CouchDB(身份验证和鉴权):控制器首先需要验证用户的身份和权限。用户的身份信息(credentials)保存在CouchDB的用户身份数据库(subjects database)中。验证无误后,控制器进行下一步处理。
- CouchDB(得到对应的Action的代码及配置): 确认用户的身份后,控制器需要从 CouchDB中读取将要被触发的函数(OpenWhisk将要执行的代码片段抽象成为 Action,为了简便,此处直接称之为函数)。函数对应的数据存储在CouchDB的whisk 数据库,主要包含要被执行的代码、默认参数、被执行代码的权限、及CPU/内存使用限制。
- Consul和负载均衡:到了这一步,控制器已经有了触发函数所需要的全部信息,在将数据发送给触发器(Invoker)之前,控制器需要和Consul确认,从Consul 获取处于空闲状态的触发器的地址。Consul 是一个开源的服务注册/发现系统,在 OpenWhisk中Consul负责记录跟踪所有触发器的状态信息。当控制器向Consul发出请求,Consul从后台随机选取一个空闲的触发器信息,并返回。
- 触发请求送进Kafka: Kafka 充当了Controller和Invoker之间的缓存,当后端 Invoker 负载过大,没有及时处理Kafka数据流中的请求时,Controller 依然可以将请求送入Kafka,无需阻塞当前线程。同时所有送进Kafka 的请求消息都会被以log的形式的形式保存在文件系统中,即使系统瘫痪,已经由 Controller发出的请求也不会丢失。
- 触发器运行用户代码: 触发器从对应的 Kafka topic 中接收控制器传来的请求,并执行响应代码。OpenWhisk 的触发器是构建在 Docker 之上的,每一个函数触发都运行在一个独立的 Docker 容器之内.
- CouchDB 保存运行结果: 触发器执行结果最终会被保存在 CouchDB 中的 whisk 数据库里, 保存的格式如下:
{
"activationId": "31809ddca6f64cfc9de2937ebd44fbb9",
"response": {
"statusCode": 0,
"result": {
"hello": "world"
}
},
"end": 1474459415621,
"logs": [
"2016-09-21T12:03:35.619234386Z stdout: Hello World"
],
"start": 1474459415595,
}
保存结果包括用户函数的返回值,及日志记录。对异步触发用户,可以通过步骤6中返回的activationID取回函数运行结果。同步触发的的结果和异步触发一样保存在 CouchDB里,控制器在得到触发结束的确认后,从CouchDB 中取得运行结果,直接返回给用户。