Kubeless
Kubeless是一个相对成熟的项目,与其他一些比较成熟的例如Fisson,OpenWhisk等开源FaaS平台相比较,他们在Github上面的Watch,Star以及Fork分别如下:
|
Watch |
Star |
Fork |
Knative |
113 |
3600 |
758 |
Kubeless |
173 |
4775 |
491 |
Fission |
147 |
4436 |
399 |
OpenWhisk |
235 |
4090 |
793 |
Kubeless是在Fission之后开源的项目,该项目也是基于K8S来实现。在官方网站(kubeless.io)中,有这样的文字,用来介绍Kubeless:
Kubeless is a Kubernetes-native serverless framework that lets you deploy small bits of code (functions) without having to worry about the underlying infrastructure. It is designed to be deployed on top of a Kubernetes cluster and take advantage of all the great Kubernetes primitives. If you are looking for an open source serverless solution that clones what you can find on AWS Lambda, Azure Functions, and Google Cloud Functions, Kubeless is for you!
Kubeless Includes:
- Support for Python, Node.js, Ruby, PHP, Golang, .NET, Ballerina and custom runtimes
- CLI compliant with AWS Lambda CLI
- Event triggers using Kafka messaging system and HTTP events
- Prometheus monitoring of functions calls and function latency by default
- Serverless Framework plugin
通过描述可以看到,Kubeless认为,Kubeless是一款和AWS Lambda,Azure Functions以及Google Cloud Functions类似的一款产品,如果想要寻找这三款产品的替代品,那么就可以尝试使用Kubeless,同时简单的介绍了Kubeless的Runtime,Enent triggers等。
功能与策略
运行时
Kubeless的运行时相对来说是比较丰富的,和OpenWhisk、Fission等相比也是不分伯仲的:
|
Kubeless |
Fission |
OpenWhisk |
Binary |
|
√ |
|
Go |
√ |
√ |
√ |
.NET |
√ |
√ |
√ |
NodeJS |
√ |
√(Alphine, Debian) |
√ |
Perl |
|
√ |
|
PHP |
√ |
√ |
√ |
Python |
√ |
√ |
|
Ruby |
√ |
√ |
√ |
Java |
√ |
√ |
√ |
Rust |
|
|
√ |
Swift |
|
|
√ |
ballerina |
√ |
|
√ |
统计 |
8 |
9 |
9 |
这其中,OpenWhisk拥有多种灵活的包内容,以Python为例包括Python2Action、Python3AiAction、PythonAction以及pythonActionLoop等,Fission相对来说比较自由,因为其支持Binary,也就是说很多语言可以以二进制形式上传,并且使用,而Kubless则不同,理论上Kubeless是可以按照某些规则自定义Runtime。
另外,对于Runtime部分,这里有一个关于代码Init的有趣对比:
|
Kubeless |
Fission |
OpenWhisk |
Init |
装载到Image中 |
POST |
POST |
在之前介绍过的Fission和OpenWhisk等开源FaaS项目中,代码放入容器的方法基本上都是通过POST形式,也就是说,容器启动,然后Init代码,容器启动过程实际上是冷启动过程,容器启动之后,对代码登记进行初始化的过程是温启动过程,这样做的目的是为了提高代码启动效率,降低冷启动率,以及降低冷启动带来的延时问题。但是在Kubeless中,这个操作则是完全不同的。Kubeless的代码初始化过程是在建立Image的时候,通过引用已有的Image,然后通过在Dockerfile中使用ADD指令,将代码等资源装载到程序中,然后在进行容器的启动以及代码的执行。相对前者而言,Fission的这种做法,实际上是针对每段代码定制化容器,这种做法带来的劣势是很难对其进行池化,或者很难对其降低冷启动率等进行优化。
触发器
在触发器层面,Fission的触发器种类,明显比Kubeless要多。这也从另一个方面说明Fission相对比Kubeless灵活一些:
|
Kubeless |
Fission |
CLI |
√ |
√ |
HTTP |
√ |
√ |
Cronjob |
√ |
√ |
Kafka |
√ |
√ |
Nats |
√ |
√ |
Kinesis |
√ |
|
Azure-Storage-Queue |
|
√ |
K8S Watch |
|
√ |
但是Kubeless是可以自定义触发器的,只要按照一定的规范和标准,Kubeless支持用户自定义触发器。
在自定义触发器部分,Kubeless的相关中文描述如下:
- 为新的事件源创建一个 CRD 来描述事件源触发器;
- 在自定义资源对象的 spec 里描述该事件源的属性,例如 KafkaTriggerSpec、HTTPTriggerSpec;
- 为该 CRD 创建一个 CRD controller;
- 该 controller 需要持续监听针对事件源触发器和 function 的 CRUD 操作并作出正确的处理;
- 当事件发生时,触发关联函数的执行;
弹性伸缩
自动伸缩策略,在OpenWhisk中表现的一般,他们定义的自动伸缩能力就是第一次启动一定是冷启动,之后会维护一种类似资源池的操作,但是严格来讲这并不算是一种自动伸缩的能力,虽然同样降低了冷启动率,但是这种做法更应该被称之外“资源池;而Fission相对来说是资源池+AS策略,但是Fission的AS策略是完全依赖HPA API V1,也就是说,只能通过CPU使用率的维度,来进行自动扩所容策略的实现;而Kubeless和Fission同样利用了Kubernetes的HPA,不同的是,Kubeless支持了基于CPU和QPS两种指标进行自动伸缩:
可以说,针对降低冷启动率(此处包括池化和自动扩缩两部分),OpenWhisk、Fission 以及Kubeless这三者做是不同的:
|
Kubeless |
Fission |
OpenWhisk |
资源池 |
|
√ |
√(类似资源池) |
自动扩缩 |
√(CPU+QPS) |
√(CPU) |
Kubeless基于CPU的自动扩容的方法和Fission方法基本一致:
kubeless autoscale create hello --metric=cpu --min=1 --max=3 --value=70
通过设置最小容器数量和最大容器数量,以及CPU使用率的值来进行,在HPA中,配置如下:
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2alpha1
metadata:
name: hello
namespace: default
labels:
created-by: kubeless
function: hello
spec:
scaleTargetRef:
kind: Deployment
name: hello
minReplicas: 1
maxReplicas: 3
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 70
在Kubernetes中计算POD数量:
TargetNumOfPods = ceil(sum(CurrentPodsCPUUtilization) / Target)
基于QPS的方法,则是Kubeless基于HPA API V2所拥有或者是所继承的特性,这一指标在HPA API V1中并不具备,所以Fission不具备该指标进行AS:
kubeless autoscale create hello --metric=qps --min=1 --max=5 --value=2k
通过这条指令,可以看到Metric的指定为qps,容器数量最小为1,最大为5,这里的Value的意思是,确保所有挂在服务 hello 后的 pod 每秒能处理的请求次数之和达到 2000。这条指令在HPA配置如下:
kind: HorizontalPodAutoscaler
apiVersion: autoscaling/v2alpha1
metadata:
name: hello
namespace: default
labels:
created-by: kubeless
function: hello
spec:
scaleTargetRef:
kind: Deployment
name: hello
minReplicas: 1
maxReplicas: 5
metrics:
- type: Object
object:
metricName: function_calls
target:
apiVersion: autoscaling/v2beta1
kind: Service
name: hello
targetValue: 2k
这里要注意一点,虽然Kubeless提供了这样两种Metric,但是实际上,还可以实现基于多项指标的,只不过需要额外的配置,需要一定的学习成本。但是不可否认,在AS这里,Kubeless做的相对更加成熟,稳定,虽然底层也是依靠K8S HPA API,但是并没有像Fission一样陈旧过时。
可视化
Kubeless这里除了Kubernetes的可视化管理之外,自己还拥有一个基于React的Web UI:
通过这个Web UI洁面可以很轻松的新建Function,修改编辑Function以及运行Function,虽然功能简单,内容不多,但是这样一个UI确实是极大的降低了开始使用的难度。除了这样的一个程序,其还提供了该程序的Docker Image等帮助用户快速构建可视化管理工具。
对比与总结
运行时:
- Kubeless提供了常见的Runtime,而且某些语言提供了多种版本,例如Python2.6,2.7,3.6,3.7等,相对来说比较丰富;
- 在提供常见的Runtime时,提供了自定义Runtime的接口,这样会让Runtime更加灵活,适用于高级使用者;
- Kubeless运行时,并不像其他语言,直接通过Docker Image,运行镜像,并且Init代码进入,而是通过现有的Docker image,将代码打包放入新的Image,然后再进行后续操作,这样的做法,带来的致命缺点,就是大大提高的冷启动率;
函数结构:
- Kubeless通过综合运用 K8s 中的多种组件以及利用各语言的动态加载能力实现了从用户源码到可执行的函数的构建逻辑;
- 考虑了函数运行的安全性,通过 Security Context 机制限制容器中的进程以非 root 身份运行。
触发器:
- Kubeless 提供了一些基本常用的触发器,如果有其他事件源也可以通过自定义触发器接入;
- 不同事件源的接入方式不同,但最终都是通过访问函数 ClusterIP 类型的 service 触发函数执行。
- 虽然提供了种类丰富的触发器,但是Kubeless并没有像Fission和OpenWhisk一样,将触发器进行编排起来,貌似也没有提供编排的策略,这就让触发场景变的捉襟见肘,而且也不够灵活;
弹性伸缩:
- Kubeless 依赖KubernetesHPA API V2,通过CPU和QPS两种指标对AS进行实现,同时也提供更高级的操作方法,即可以自定义指标组合;
- 由于过分的依赖KubernetesHPA,所以Kubeless也继承了他的一些特性,即POD数量不能小于1,这在FaaS平台显得不是很合常理,因为某些函数用户建立完成,可能使用之后会放在哪里很久,这个时候可以降低到0以节约资源,但是Kubeless却不能实现;
- 目前的自动扩所容策略,更多的是依靠规则,而不是通过预测;但是不可否认,相对Fission和OpenWhisk已经做得很好了。