Knative serverless架构详解

标签: | 发表时间:2021-08-21 09:34 | 作者:
出处:http://www.uml.org.cn
编辑推荐:
Nginx 服务器是一个高性能的 Web 和反向代理服务器。Nginx 在激烈的 Web 服务器竞争中依旧保持良好的发展势头,一度成为 Web 服务器市场的后期之秀,这一切跟 Nginx 的架构设计是分不开的。
来自于my.oschina.net,,由火龙果软件Alice编辑、推荐。

serverless

无服务器架构(serverless),则表示代码可以只在需要时运行,在不需要时就停止,从而让你的基础设施能在其他方面自由使用计算资源。

Kaniko

Kaniko 是 Google 造的轮子之一,用于在 Kubernetes 上无需特权的构建 docker image,在 github中,是这样介绍的。

工作原理

传统的 Docker build 是 Docker daemon 根据 Dockerfile,使用特权用户(root)在宿主机依次执行,并生成镜像的每一层:

而 Kaniko 工作原理和此类似,也是按顺序执行每条命令,每条命令执行完毕后为文件系统做快照(snapshot)。并与上一个快照进行对比,如果发现任何不一致,变回创建一个新的层级,并将任何修改都写入镜像的元数据中。

什么是 Knative

Knative 的目标是在基于 Kubernetes 之上为整个开发生命周期提供帮助。它的具体实现方式是:首先使你作为开发人员能够以你想要的语言和以你想要的方式来编写代码,其次帮助你构建和打包应用程序,最后帮助你运行和伸缩应用程序。

Knative 主要由 Build、Serving 和 Eventing 三大核心组件构成。Knative 正是依靠这三个核心组件,驱动着 Knative 这艘 Serverless 巨轮前行。下面让我们来分别介绍一下这三个核心组件。

build

通过灵活的插件化的构建系统将用户源代码构建成容器。目前已经支持多个构建系统,比如 Google 的 Kaniko,它无需运行 Docker

daemon 就可以在 Kubernetes 集群上构建容器镜像。

Knative Build 是基于现有的 Kubernetes 能力之上,提供的一套标准化、可移植、可复用的容器镜像构建方式。通过在 Kubernetes 上运行复杂的构建任务,Knative Build 使你不必再单独开发和重复这些镜像构建过程, 从而通过系统化、工程化的方式,减少了镜像构建时间及成本。

Build 通过 Kubernetes 自定义资源定义(CRD)实现。 通过 Build 你可以自定义一个从运行到结束的构建流程。例如,可以使用 Knative Build 来获取、构建和打包代码。Build 具备以下功能:

支持 Source 源挂载,目前支持的 Source 源包括:

�C git 代码仓库

�C 任意容器镜像

支持通过 BuildTemplate 创建可重复执行构建的模板

支持 K8s ServiceAccount 身份验证

虽然目前 Knative Build 并不提供完整的独立 CI/CD 解决方案,但它却提供了一个底层的构建模块,用户可单独使用该构建模块在大型系统中实现集成和利用。

Serving

基于负载自动伸缩,包括在没有负载时缩减到零。允许你为多个修订版本(revision)应用创建流量策略,从而能够通过 URL轻松路由到目标应用程序。

Knative 作为 Severless 框架最终是用来提供服务的, 那么 Knative Serving 应运而生。

Knative Serving 构建于 Kubernetes 和 Istio 之上,为 Serverless 应用提供部署和服务支持。其特性如下:

快速部署 Serverless 容器

支持自动扩缩容和缩到 0 实例

基于 Istio 组件,提供路由和网络编程

支持部署快照

Knative Serving 中定义了以下 CRD 资源:

Service: 自动管理工作负载整个生命周期。负责创建 Route、Configuration 以及 Revision 资源。通过 Service 可以指定路由流量使用最新的 Revision 还是固定的 Revision

Route:负责映射网络端点到一个或多个 Revision。可以通过多种方式管理流量。包括灰度流量和重命名路由

Configuration: 负责保持 Deployment 的期望状态,提供了代码和配置之间清晰的分离,并遵循应用开发的 12 要素。修改一次 Configuration 产生一个 Revision

Revision:Revision 资源是对工作负载进行的每个修改的代码和配置的时间点快照。Revision 是不可变对象,可以长期保留

Configuration(配置)和 Revision(修订版本)

Knative Serving 始于 Configuration。您可以在 Configuration 中为部署定义所需的状态。最小化 Configuration 至少包括一个配置名称和一个要部署容器镜像的引用。在 Knative 中,定义的引用为 Revision。Revision 代表一个不变的,某一时刻的代码和 Configuration 的快照。每个 Revision 引用一个特定的容器镜像和运行它所需要的任何特定对象(例如环境变量和卷)。然而,您不必显式创建 Revision。由于 Revision 是不变的,它们从不会被改变和删除,相反,当您修改 Configuration 的时候,Knative 会创建一个 Revision。这允许一个 Configuration 既反映工作负载的当前状态,同时也维护一个它自己的历史 Revision 列表。

例如:

apiVersion: serving.knative.dev/v1alpha1
kind: Configuration
metadata:
name: knative-helloworld
namespace: default
spec:
revisionTemplate:
spec:
container:
image: docker.io/gswk/knative-helloworld:latest
env:
- name: MESSAGE
value: "Knative!"
ports:
- containerPort: 8081

其中默认情况下,Knative 将假定您的应用程序监听 8080 端口。

Configuration 可以指定一个已有的容器镜像,如示例 2-1 中所示。或者,它也可以选择指向一个 Build 资源以从源代码创建一个容器镜像。

Knative 转换 Configuration 定义为一些 Kubernetes 对象并在集群中创建它们。在启用 Configuration 后,可以看到相应的 Deployment、ReplicaSet 和 Pod。

现在我们有了用于运行我们应用的 Pod,但是我们怎么知道该向哪里发送请求?这正是 Route 用武之地。

Route(路由)

Knative 中的 Route 提供了一种将流量路由到正在运行的代码的机制。它将一个命名的,HTTP 可寻址端点映射到一个或者多个 Revision。Configuration 本身并不定义 Route

apiVersion: serving.knative.dev/v1alpha1
kind: Route
metadata:
name: knative-helloworld
namespace: default
spec:
traffic:
- configurationName: knative-helloworld
percent: 100

这里展示了一个将流量发送到指定 Configuration 最新 Revision 的最基本路由定义。

这个定义中,Route 发送 100% 流量到由 configurationName 属性指定 Configuration 的最新就绪 Revision,该 Revision 由 Configuration YAML 中 latestReadyRevisionName 属性定义。您可以通过发送如下 curl 命令来测试这些 Route 和 Configuration :

curl -H "Host: knative-routing -demo.default.example.com"
http://$KNATIVE_INGRESS

你可以通过指定流量版本名称进行abtest

apiVersion: serving.knative.dev/v1alpha1
kind: Route
metadata:
name: knative-routing-demo
namespace: default
spec:
traffic:
- revisionName: knative-routing-demo-00001
name: v1
percent: 100

指定的 Revision 可以使用 v1 子域名访问,如下 curl 命令所示:

curl -H "Host: v1.knative-routing-demo.default.example.com"
http://$KNATIVE_INGRESS

Knative 也允许以百分比的方式跨 Revision 进行流量分配。支持诸如增量发布、蓝绿部署或者其他复杂的路由场景

注意:Knative 默认使用 example.com 域名,但不适合生产使用。您会注意到在 curl 命令 (v1.knative-routing-demo.default.example.com) 中作为一个主机头传递的 URL 包含该默认值作为域名后缀。URL 格式遵循模式 {REVISION_NAME}.{SERVICE_NAME}.{NAMESPACE}.{DOMAIN} 。

在这个案例中,子域名中 default 部分指的是命名空间。

下面我们来看看如何改变这些值以及如何使用自定义域名。

Autoscaler(自动伸缩器)和 Activator(激活器)

Serverless 的一个关键原则是可以按需扩容以满足需要和缩容以节省资源。Serverless 负载应当可以一直缩容至零。这意味着如果没有请求进入,则不会运行容器实例。Knative 使用两个关键组件以实现该功能。它将 Autoscaler 和 Activator 实现为集群中的 Pod。您可以看到它们伴随其他 Serving 组件一起运行在 knative-serving 命名空间中.

Autoscaler 收集打到 Revision 并发请求数量的有关信息。为了做到这一点,它在 Revision Pod 内运行一个称之为 queue-proxy 的容器,该 Pod 中也运行用户提供的 (user-provided) 镜像。可以在相应 Revision Pod 上,通过运行 kubectl describe 命令可以看到这些容器

...
Containers:
user-container:
Container ID: docker://f02dc...
Image: index.docker.io/gswk /knative-helloworld...
...
queue-proxy:
Container ID: docker://1afcb...
Image: gcr.io/knative-releases /github.com/knative...
...

queue-proxy 检测该 Revision 上观察到的并发量,然后它每隔一秒将此数据发送到 Autoscaler。Autoscaler 每两秒对这些指标进行评估。基于评估的结果,它增加或者减少 Revision 部署的规模。

默认情况下,Autoscaler 尝试维持每 Pod 每秒平均 100 个并发请求。这些并发目标和平均并发窗口均可以变化。Autoscaler 也能够被配置为利用 Kubernets HPA (Horizontal Pod Autoscaler) 来替代该默认配置。

这将基于 CPU 使用率来自动伸缩但不支持缩容至零。这些设定都能够通过 Revision 元数据注解 (annotations) 定制。有关这些注解的详情,请参阅 Knative 文档。https://knative.dev/blog/

例如,一个 Revision 每秒收到 350 个请求并且每次请求大约需要处理 0.5 秒。使用默认设置 (每 Pod 100 个并发请求),这个 Revision 将扩展至两个 Pod:

350 * .5 = 175
175 / 100 = 1.75
ceil(1.75) = 2 pods

Autoscaler 也负责缩容至零。Revision 处于 Active (激活) 状态才接受请求。当一个 Revision 停止接受请求时,Autoscaler 将其置为 Reserve (待命) 状态,条件是每 Pod 平均并发必须持续 30 秒保持为 0 (这是默认设置,但可以配置)。

处于 Reserve 状态下,一个 Revision 底层部署缩容至零并且所有到它的流量均路由至 Activator。Activator 是一个共享组件,其捕获所有到待命 Revisios 的流量。当它收到一个到某一待命 Revision 的请求后,它转变 Revision 状态至 Active。然后代理请求至合适的 Pods。

Autoscaler 如何伸缩

Autoscaler 采用的伸缩算法针对两个独立的时间间隔计算所有数据点的平均值。它维护两个时间窗,分别是 60 秒和 6 秒。Autoscaler 使用这些数据以两种模式运作:Stable Mode (稳定模式) 和 Panic Mode (忙乱模式)。在 Stable 模式下,它使用 60 秒时间窗平均值决定如何伸缩部署以满足期望的并发量。

如果 6 秒窗口的平均并发量两次到达期望目标,Autoscaler 转换为 Panic Mode 并使用 6 秒时间窗。这让它更加快捷的响应瞬间流量的增长。它也仅仅在 Panic Mode 期间扩容以防止 Pod 数量快速波动。如果超过 60 秒没有扩容发生,Autoscaler 会转换回 Stable Mode。

serving

在 Knative 中,Service 管理负责的整个生命周期。包括部署、路由和回滚。(不要将 Knative Service 和 Kubernetes Service 混淆。它们是不同的资源。) Knative Service 控制一系列组成软件的 Route 和 Configuration。Knative Service 可以被看作是一段代码 ―― 您正在部署的应用或者函数。

一个 Service 注意确保一个应用有一个 Route、一个 Configuation,以及为每次 Service 更新产生的一个新 Revision。当创建一个 Service 时,您没有特别定义一个 Route,Knative 创建一个发送流量到最新 Revision 的路由。您可以选择一个特定的 Revision 以路由流量到该 Revision。

不要求您明确创建一个 Service。Route 和 Configuration 可以被分开在不同的 YAML 文件(如示例 2-1 和 示例 2-4)。在这种情形下,您可以应用每个单独的对象到集群。然而,推荐的方式使用一个 Service 来编排 Route 和 Configuration。

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: knative-helloworld
namespace: default
spec:
runLatest:
configuration:
revisionTemplate:
spec:
container:
image: docker.io/gswk/knative-helloworld:latest

注意这个 service.yml 文件和 configuration.yml 非常相似。这个文件定义 Configuration 并且是最小化 Service 定义。由于这里没有 Route 定义,一个默认 Route 指向最新 Revision。Service 控制器整体追踪它所有的 configuration 和 Route 的状态。然后反映这些状态在它的 ConfigurationsReady 和 RoutesReady conditions 属性里。当通过 CLI 使用 kubectl get ksvc 命令请求 Knative Service 信息的时候,这些状态可以被看到。

kubectl get ksvc xxx -o yaml

apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
...
name: knative-helloworld
namespace: default
...
spec:
...
status:
conditions:
- lastTransitionTime: YYYY-MM-DDTHH:MM:SSZ
status: "True"
type: ConfigurationsReady
- lastTransitionTime: YYYY-MM-DDTHH:MM:SSZ
status: "True"
type: Ready
- lastTransitionTime: YYYY-MM-DDTHH:MM:SSZ
status: "True"
type: RoutesReady
domain: knative -helloworld.default.example.com
domainInternal: knative-helloworld.default.svc.cluster.local
latestCreatedRevisionName: knative-helloworld-00001
latestReadyRevisionName: knative-helloworld-00001
observedGeneration: 1
targetable:
domainInternal: knative -helloworld.default.svc.cluster.local
traffic:
- percent: 100
revisionName: knative -helloworld-00001

总结

至此已经向您介绍了 Service、Route、Configuration 和 Revision。Revision 是不变的并且只能经由 Configuration 改变而被创建。您可以分别单独创建 Configuration 和 Route,或者把它们组合在一起并定义为一个 Service。理解 Serving 组件的这些构建块是使用 Knative 的基础。您部署的应用均需要一个 Service 或者 Configuration 以在 Knative 中作为容器运行。

Eventing

使得生产和消费事件变得容易。抽象出事件源,并允许操作人员使用自己选择的消息传递层。

Knative Eventing 旨在满足云原生开发中通用需求, 以提供可组合的方式绑定事件源和事件消费者。其设计目标:

Knative Eventing 提供的服务是松散耦合,可独立开发和部署。服务可跨平台使用(如 Kubernetes, VMs, SaaS 或者 FaaS)

事件的生产者和事件的消费者是相互独立的。任何事件的生产者(事件源)可以先于事件的消费者监听之前产生事件,同样事件的消费者可以先于事件产生之前监听事件

支持第三方的服务对接该 Eventing 系统

确保跨服务的互操作性

如上图所示,Eventing 主要由事件源(Event Source)、事件处理(Flow)以及事件消费者(Event Consumer)三部分构成。

事件源(Event Source)

当前支持以下几种类型的事件源:

ApiserverSource:每次创建或更新 Kubernetes 资源时,ApiserverSource 都会触发一个新事件

GitHubSource:GitHub 操作时,GitHubSource 会触发一个新事件

GcpPubSubSource: GCP 云平台 Pub/Sub 服务会触发一个新事件

AwsSqsSource:Aws 云平台 SQS 服务会触发一个新事件

ContainerSource: ContainerSource 将实例化一个容器,通过该容器产生事件

CronJobSource: 通过 CronJob 产生事件

KafkaSource: 接收 Kafka 事件并触发一个新事件

CamelSource: 接收 Camel 相关组件事件并触发一个新事件

事件接收/转发(Flow)

当前 Knative 支持如下事件接收处理:

直接事件接收

通过事件源直接转发到单一事件消费者。支持直接调用 Knative Service 或者 Kubernetes Service 进行消费处理。这样的场景下,如果调用的服务不可用,事件源负责重试机制处理。

通过事件通道(Channel)以及事件订阅(Subscriptions)转发事件处理

这样的情况下,可以通过 Channel 保证事件不丢失并进行缓冲处理,通过 Subscriptions 订阅事件以满足多个消费端处理。

通过 brokers 和 triggers 支持事件消费及过滤机制

从 v0.5 开始,Knative Eventing 定义 Broker 和 Trigger 对象,实现了对事件进行过滤(亦如通过 ingress 和 ingress controller 对网络流量的过滤一样)。

通过定义 Broker 创建 Channel,通过 Trigger 创建 Channel 的订阅(subscription),并产生事件过滤规则。

事件消费者(Event Consumer)

为了满足将事件发送到不同类型的服务进行消费, Knative Eventing 通过多个 k8s 资源定义了两个通用的接口:

Addressable 接口提供可用于事件接收和发送的 HTTP 请求地址,并通过status.address.hostname字段定义。作为一种特殊情况,Kubernetes Service 对象也可以实现 Addressable 接口

Callable 接口接收通过 HTTP 传递的事件并转换事件。可以按照处理来自外部事件源事件的相同方式,对这些返回的事件做进一步处理

当前 Knative 支持通过 Knative Service 或者 Kubernetes Service 进行消费事件。

另外针对事件消费者,如何事先知道哪些事件可以被消费? Knative Eventing 在最新的 0.6 版本中提供 Registry 事件注册机制, 这样事件消费者就可以事先通过 Registry 获得哪些 Broker 中的事件类型可以被消费。

总结

Knative 使用 Build 提供云原生“从源代码到容器”的镜像构建能力,通过 Serving 部署容器并提供通用的服务模型,同时以 Eventing 提供事件全局订阅、传递和管理能力,实现事件驱动。这就是 Knative 呈现给我们的标准 Serverless 编排框架。

相关 [knative serverless 架构] 推荐:

Knative serverless架构详解

- -
服务器是一个高性能的 Web 和反向代理服务器. Nginx 在激烈的 Web 服务器竞争中依旧保持良好的发展势头,一度成为. Web 服务器市场的后期之秀,这一切跟 Nginx 的架构设计是分不开的. 来自于my.oschina.net,,由火龙果软件Alice编辑、推荐. 无服务器架构(serverless),则表示代码可以只在需要时运行,在不需要时就停止,从而让你的基础设施能在其他方面自由使用计算资源.

谈Serverless无服务器架构和应用场景(201013)

- - 人月神话的BLOG
对于云原生解决方案中涉及到的微服务,DevOps,容器云和ServiceMesh等内容,在前面很多文章都已经谈到过,今天准备谈下对Serverless架构的一些理解. 实际上要完全理解Serverless无服务器架构是一件相对困难的事情,包括到现在我的认知里面仍然认为这种架构是无法满足传统IT应用系统的架构转型和迁移的,只能够应用到一些特定的场景.

Serverless:微服务架构的终极模式

- - DockOne.io
微服务的生态和实践已经比较成熟,其设计方法、开发框架、CI/CD工具、基础设施管理工具等,都可以帮助企业顺利实施微服务. 然而,微服务远没有达到完美,它在架构、开发、基础设施方面仍然面临新的挑战. 微服务的粒度影响服务的交付速度及扩展性,微服务的开发引入治理组件,增加了开发的难度,以容器为基础的微服务基础设施在弹性等方面仍有不足,而微服务增加带来的基础设施成本也是微服务实施的新挑战.

Serverless 初探

- - 掘金 前端
广义的 Serverless :构建和运行软件时不需要关心服务器的一种架构思想. 虽然 Serverless 翻译过来是 “无服务器”,但这并不代表着应用运行不需要服务器,而是开发者不需要关心服务器. 而基于 Serverless 思想实现的软件架构就是 Serverless 架构. 现阶段关于 Serverless 的实现主要是基于 FaaS(函数即服务) 和 BaaS (后端即服务)的方案.

阿里Serverless架构落地实践:人力节省50%,研发效能提升40%

- - InfoQ推荐
作为一名阿里老兵,杨皓然早在 2010 年即加入阿里云,曾深度参与阿里云飞天分布式系统研发和产品迭代的全过程. 如今,他是阿里云 Serverless 负责人. Serverless 有哪些典型的应用场景. Serverless 在研发效能上可以发挥怎样的作用. Serverless 在阿里内部有哪些实践.

使用Knative来作为API聚合层的实践 | Yisa's Blog

- -
在2019年的今天,微服务这个词相信对于绝大多数的开发者都已经不再陌生. 时至今日,非常多的项目都逐渐开始实践起微服务这一设计思想,将原本的磐石应用逐渐按照领域模型切分成一个个小的服务,对于微服务的实践也日渐趋向于成熟. 在笔者目前工作的业务实践中,同样也使用着微服务作为后端服务的架构设立思想,微服务为我们的代码管理与项目管理带来了非常大的简便性.

Serverless/FaaS 的现状和未来

- - 午夜咖啡
FaaS 是一种新兴的技术平台,个人认为 2018 年即将迎来 FaaS 的崛起. 本文给大家提供一个 Serverless/FaaS 的现状与未来的报告,也作为自己的年度技术总结. 什么是 Serverless/FaaS. 但传统的 Application PaaS 平台,开发者对服务运行的实例还是有感的,即便是没有调用,也依然需要占用资源,并对资源付费,并不是完全的 Serverless,直到 FaaS 出现.

Serverless 的初心、现状和未来

- -
作者 | 不瞋  阿里云高级技术专家. 导读:Serverless 是如何产生的. Serverless 的未来又将如何. 本文分享了阿里云高级技术专家不瞋对于 Serverless 的看法,回顾其发展历程,并对 Serverless 的发展趋势做出预测. 回望整个计算机技术发展史,我们会发现 “抽象、解耦、集成” 的主题贯穿其中.

引入:从云计算到Serverless

- - InfoQ推荐
自世界第一台通用计算机ENIAC(Electronic Numerical Integrator And Computer, 如图1)诞生以来,计算机科学与技术的发展就从未停止过前进的脚步,尤其是近些年计算机的发展更是日新月异,有不断突破和进化的人工智能领域,有5G带来更多机会的物联网领域,还有“可信“的区块链技术,当然也有不断更新、不断迭代,不断走进“寻常百姓家”的云计算.

Serverless实战:打造个人阅读追踪系统 – ThoughtWorks洞见

- -
阅读习惯和个人知识管理体系. 进入互联网时代,知识的获取成本变得前所未有的低廉,但是无论再好的知识,若是没有对个人产生价值的话,那也只不过是一种信息噪音而已. 我在《个人知识管理:知识的三种形态》这篇文章中使用“材料 -> 资料 -> 知识”这样的路径来诠释信息的流通,如何方便快捷并且有效地收集材料,再将其整理转化为有价值的个人知识体系结构,在这个信息极度碎片化的时代变得尤为重要.