knative 核心概念和原理、应用场景和思考
什么是 Knative?
knative 是谷歌开源的 serverless 架构方案,旨在提供一套简单易用的 serverless 方案,把 serverless 标准化。目前参与的公司主要是 Google、Pivotal、IBM、Red Hat,2018年7月24日才刚刚对外发布,当前还处于快速发展的阶段。
这是 Google Cloud Platform 宣布 knative 时给出的介绍:
Developed in close partnership with Pivotal, IBM, Red Hat, and SAP, Knative pushes Kubernetes-based computing forward by providing the building blocks you need to build and deploy modern, container-based serverless applications.
可以看出,knative 是为了解决容器为核心的 serverless 应用的构建、部署和运行的问题。
serverless 的概念已经出现蛮久了,为了理解 serverless 可以从应用开发者的角度来看,使用 serverless 框架之后,应用开发者的整个操作流程就变成了:
~ # 编写 code 和 configuration 文件
~ # faascli build
~ # faascli deploy
~ # curl http://myapp.com/hello
hello, world from Awesome FaaS App!复制代码
可以看到用户只需要编写代码(或者函数),以及配置文件(如何 build、运行以及访问等声明式信息),然后运行 build 和 deploy 就能把应用自动部署到集群(可以是公有云,也可以是私有的集群)。
其他事情都是 serverless 平台(比如这里的 knative)自动处理的,这些事情包括:
- 自动完成代码到容器的构建
- 把应用(或者函数)和特定的事件进行绑定:当事件发生时,自动触发应用(或者函数)
- 网络的路由和流量控制
- 应用的自动伸缩
和标准化的 FaaS 不同,knative 期望能够运行所有的 workload : traditional application、function、container。
knative 是建立在 kubernetes 和 istio 平台之上的,使用 kubernetes 提供的容器管理能力(deployment、replicaset、和 pods等),以及 istio 提供的网络管理功能(ingress、LB、dynamic route等)。
knative 核心概念和原理
为了实现 serverless 应用的管理,knative 把整个系统分成了三个部分:
- Build:构建系统,把用户定义的函数和应用 build 成容器镜像
- Serving:服务系统,用来配置应用的路由、升级策略、自动扩缩容等功能
- Eventing:事件系统,用来自动完成事件的绑定和触发
Build 构建系统
build 的功能是把用户的代码自动化构建成容器镜像,初次听起来很奇怪,有了 docker 之后有一个 Dockerfile 不就能构建容器了吗?为什么还需要一个新的 Build 系统?
Knative 的特别之处在于两点:一是它的构建完成是在 kubernetes 中进行的,和整个 kubernetes 生态结合更紧密;另外,它旨在提供一个通用的标准化的构建组件,可以作为其他更大系统中的一部分。
正如官方文档中的说的那样,更多是为了定义标准化、可移植、可重用、性能高效的构建方法:
The goal of a Knative build is to provide a standard, portable, reusable, and performance optimized method for defining and running on-cluster container image builds.
Knative 提供了 Build
CRD 对象,让用户可以通过 yaml 文件定义构建过程。一个典型的 Build
配置文件如下:
apiVersion: build.knative.dev/v1alpha1
kind: Build
metadata:
name: example-build
spec:
serviceAccountName: build-auth-example
source:
git:
url: https://github.com/example/build-example.git
revision: master
steps:
- name: ubuntu-example
image: ubuntu
args: ["ubuntu-build-example", "SECRETS-example.md"]
steps:
- image: gcr.io/example-builders/build-example
args: ['echo', 'hello-example', 'build']
复制代码
其中,serviceAccountName
是构建过程中需要用到的密码和认证信息(比如连接到 git repo 的 SSH keys、push 镜像到 registry 的用户名和密码等);source
是代码信息,比如这里的 git 地址和分支;steps
是真正运行过程中的各个步骤,这个示例中的步骤只是作为 demo,真正的构建过程一般是 pull 代码、 build 镜像和 push镜像到 registry 等逻辑。
因为大部分的构建过程都是一致的,因此 knative 还提供了 Build template
的概念,Build template 封装了预先定义好的构建过程(就是封装了上面的 steps
过程),并提供了非常简单的配置参数来使用。
使用 build template 构建容器镜像就更简单了,只需要提供代码的地址和镜像名字即可,比如下面是使用 Google kaniko 模板构建 github 源码的 yaml 文件(需要在代码根目录存在 Dockerfile 文件):
apiVersion: build.knative.dev/v1alpha1
kind: Build
metadata:
name: kaniko-build
spec:
serviceAccountName: build-bot
source:
git:
url: https://github.com/my-user/my-repo
revision: master
template:
name: kaniko
arguments:
- name: IMAGE
value: us.gcr.io/my-project/my-app复制代码
Serving:服务系统
serving 的核心功能是让应用运行起来提供服务。虽然听起来很简单,但这里包括了很多的事情:
- 自动化启动和销毁容器
- 根据名字生成网络访问相关的 service、ingress 等对象
- 监控应用的请求,并自动扩缩容
- 支持蓝绿发布、回滚功能,方便应用方法流程
knative serving 功能是基于 kubernetes 和 istio 开发的,它使用 kubernetes 来管理容器(deployment、pod),istio 来管理网络路由(VirtualService、DestinationRule)。
因为 kubernetes 和 istio 本身的概念非常多,理解和管理起来比较困难,knative 在此之上提供了更高一层的抽象(这些对应是基于 kubernetes 的 CRD 实现的)。这些抽象出来的概念对应的关系如下图:
- Configuration:应用的最新配置,也就是应用目前期望的状态,对应了 kubernetes 的容器管理(deployment)。每次应用升级都会更新 configuration,而 knative 也会保留历史版本的记录(图中的 revision),结合流量管理,knative 可以让多个不同的版本共同提供服务,方便蓝绿发布和滚动升级
- Route:应用的路由规则,也就是进来的流量如何访问应用,对应了 istio 的流量管理(VirtualService)
- Service:注意这里不是 kubernetes 中提供服务发现的那个 service,而是 knative 自定义的 CRD,它的全称目前是
services.serving.knative.dev
。单独控制 route 和 configuration 就能实现 serving 的所有功能,但knative 更推荐使用 Service 来管理,因为它会自动帮你管理 route 和 configuration - pod 会自动汇报 metrics 数据到 autoscaler,autoscaler 会根据请求量和资源使用情况修改 deployment 的 replicas 数量,从而实现自动扩缩容。serverless 一个重要的特定是它会 scale to 0 的,也就是当应用没有流量访问时,它会自动销毁所有的 pod
- activator 比较有趣,它是为了处理 scale to 0 而出现的。当某个 revision 后面的 pod 缩容到 0 时,route 的流量会指向 activator,activator 接收到请求之后会自动拉起 pod,然后把流量转发过去
- route 对象对应了 istio 的 DestinationRoute 和 VirtualService,决定了访问应用的流量如何路由
- Feed:把某种类型的 EventType 和 EventSource 和对应的 Channel 绑定到一起
- Channel:对消息实现的一层抽象,后端可以使用 kafka、RabbitMQ、Google PubSub 作为具体的实现。channel name 类似于消息集群中的 topic,可以用来解耦事件源和函数。事件发生后 sink 到某个 channel 中,然后 channel 中的数据会被后端的函数消费
- Subscription:把 channel 和后端的函数绑定的一起,一个 channel 可以绑定到多个knative service
- 如何知道一个函数的功能是什么?接受的参数是什么?
- 怎么保证函数的升级不会破坏原有的功能?升级之后如何回滚?怎么记录函数的历史版本一方面追溯?
- 当有多个函数需要同时工作的时候,怎么定义它们之间的关系?
- 函数出现问题的时候如何调试?
- 支持的事件源和消息系统还还优先,外部事件只支持 github、kubernetes 和 Google PubSub。 这个问题可以慢慢扩展,knative 本身会实现很常用的事件类型,自定义的事件源用户可以自己实现
- 目前还没有函数的 pipeline 管理(类似 AWS Lambda Step Functions),多个函数如何协作并没有自己处理。虽然没有在官方文档中看到这方面的 roadmap,但是以后一定会有这方面的功能(不管是 knative 本身来做,还是社区作为工具补充来实现)