华为云云原生钻石集训营 第二课:Kubernetes技术架构深度剖析

成长的小咘咘 秀才 2022-05-09 19:56:26

学完本课程后,您将能够:

了解Kubernetes系统架构

controller控制器原理详解

了解list-watch机制原理

 

本节课,详细讲解kubernetes核心机制的实现原理和设计精髓,包括List-Watch机制和Informer模块,以及kubernetes controller机制原理。

 

一、Kubernetes系统架构详解

Kubermnetes是Google开源的容器集群管理系统;它构建在容器技术之上,为容器化的应用提供资源调度,部署运行,服务发现,扩容缩容等一整套功能,本质上是基于容器技术的Micro-PaaS平台,Kubernetes的灵感来源于Google内部的Borg系统

将容器宿主机组成集群,统一进行资源调度,自动管理容器生命周期,提供跨节点服务发现和负载均衡;更好的支持微服务理念,划分、细分服务之间的边界,比如lablel、pod等概念的引入

轻量,迁移方便,部署快捷,插件化,可扩展

 

 

二、controller控制器原理详解

Kubernetes Controller Manager原理解析

Controller Manager是集群内部的管理控制中心,负责统一管理与运行不同的Controller,实现对集群内的Node、Pod等所有资源的管理。比如当通过 Deployment 创建的某个Pod 发生异常退出时,RSController便会接受并处理该退出事件,并创建新的 Pod 来维持预期副本数。

controller manager起什么作用?

k8s内部几乎每种特定资源都有特定的Controller维护管理,而Controller Manager的职责便是把所有的Controller聚合起来:

1.提供基础设施降低Controller的实现复杂度

2.启动和维持Controller的正常运行,watch api-server,然后对不同的Controller分发事件通知。

k8s中有几十种Controller,这里列举一些相对重要的Controller:

1.部署控制器(Deployment Controller):负责pod的滚动更新、回滚以及支持副本的水平扩容等。

2.节点控制器(Node Controller):负责在节点出现故障时进行通知和响应。

3.副本控制器(Replication Controller):负责为系统中的每个副本控制器对象维护正确数量的Pod。

4.端点控制器(Endpoints Controller):填充端点(Endpoints)对象(即加入Service与Pod)。

5.服务帐户和令牌控制器(Service Account & Token Controllers):为新的命名空间创建默认帐户和API访问令牌

6. ...….

Controller的eventHandler如何注册?

在pkg/controller/deployment/deployment controllergo的NewDeploymentController方法中,便包括了Event Handler的注册,对于Deployment Controller 来说,只需要根据不同的事件实现不同的处理逻辑,便可以实现对相应资源的管理。

AddEventHandler被封装成ProcessListener并添加到数组中,并且调用了ProcessListener的run方法。

Controller的eventHandler如何注册?

processorListener的run方法就是一个work,消费注册的Handler

Controller的eventHandler注册上了,client-go如何监听api-server并分发event事件的呢?

kubernetes在github 上提供了一张client-go的架构图,从中可以看出,Controller 正是下半部分(CustomController)描述的内容,而client-go主要完成的是上半部分。

client-go组件:

1. Reflector: reflector用来watch特定的k8s API资源。具体的实现是通过ListAndWatch的方法,watch可以是k8s内建的资源或者是自定义的资源。当reflector通过watch API接收到有关新资源实例存在的通知时,它使用相应的列表API获取新创建的对象,并将其放入watchHandler函数内的DeltaFifo队列中。

2. Informer: informer从Delta Fifo队列中弹出对象。执行此操作的功能是processLoop。base controller的作用是保存对象以供以后检索,并调用我们的控制器将对象传递给它。

3. Indexer:索引器提供对象的索引功能。典型的索引用例是基于对象标签创建索引。Indexer可以根据多个索引函数维护索引。Indexer使用线程安全的数据存储来存储对象及其键。在Store中定义了一个名为MetaNamespaceKeyFunc的默认函数,该函数生成对象的键作为该对象的<namespace> / <name>组合。

 

自定义controller组件:

1. Informer reference:指的是Informer实例的引用,定义如何使用自定义资源对象。自定义控制器代码需要创建对应的Informer。

2. Indexer reference:自定义控制器对Indexer实例的引用。自定义控制器需要创建对应的Indexer。

client-go中提供Newlndexerlnformer函数可以创建Informer 和Indexer。

1. Resource Event Handlers:资源事件回调函数,当它想要将对象传递给控制器时,它将被调用。编写这些函数的典型模式是获取调度对象的key,并将该key排入工作队列以进行进—步处理。

2. Workqueue:任务队列。编写资源事件处理程序函数以提取传递的对象的key并将其添加到任务队列。

3.Process Item:处理任务队列中对象的函数,这些函数通常使用Indexer引用或Listing包装器来重试与该key对应的对象。

 

三、list-watch机制原理详解

lnformer封装list-watch

K8S的informer模块封装list-watch API,用户只需要指定资源,编写事件处理函数,AddFunc,UpdateFunc和DeleteFunc等。

Informer是Client-go中的一个核心工具包。为了让Client-go更快地返回Lit/Get请求的结果、减少对Kubenetes AP)的直接调用,Informer被设计实现为一个依赖Kubernetes List/Watch API、可监听事件并触发回调函数的二级缓存工具包。

Informer设计实现

lnformer组件:

1. Controller 用于处理收到的事情,触发Processor中的回调函数

2.Reflector:通过Kubernetes Watch API监听resource下的所有事件

3.Lister:用来被调用List/Get方法

4.Processor:记录并触发回调函数.

DeltaFIFO            LocalStore

DeltaFIFO和LocalStore是Informer的两级缓存。DeltaFIFO:用来存储Watch API返回的各种事件。LocalStore: Lister的List/Get方法访问。

 

Kubernetes核心机制list-watch

List-watch是K8S统一的异步消息处理机制,各组件间协同都采用该机制进行通信。List-watch机制保证了消息的实时性,可靠性,顺序性,性能等等,为声明式风格的APlI奠定了良好的基础,它是优雅的通信方式,是K8S架构的精髓。对系统的性能、数据一致性起到关键性的作用。

list-watch操作主要完成以下几个事情:

1. Watch核心数据存储是etcd,是典型的发布-订阅模式。但不直接访问etcd,通过apiserver发起请求,在组件启动时进行订阅。

2.可以带条件向apiserver发起的watch请求。例如,scheduler想要watch的是所有未被调度的Pod来进行调度操作;而kubelet只关心自己节点上的Pod列表。

apiserver向etcd发起的watch是没有条件的,只能知道某个数据发生了变化或创建、删除,但不能过滤具体的值。也就是说对象数据的条件过滤必须在apiserver端而不是etcd端完成。

3. list是watch失败,数据太过陈旧后的弥补手段,这方面详见基于lst-watch的Kubernetes异步事件处理框架详解-客户端部分。list本身是一个简单的列表操作。

 

Watch是如何实现的?

List的实现容易理解,那么Watch是如何实现的呢? Watch是如何通过HTTP长链接接收apiserver发来的资源变更事件呢?

秘诀就是Chunked transfer encoding(分块传输编码),它首次出现在HTTP/1.1。

HTT分块传输编码允许服务器为动态生成的内容维持HTTP持久链接。通常,持久链接需要服务器在开始发送消息体前发送Content-Length消息头字段,但是对于动态生成的内容来说,在内容创建完之前是不可知的。使用分块传输编码,数据分解成一系列数据块,并以一个或多个块发送,这样服务器可以发送数据而不需要预先知道发送内容的总大小。

当客户端调用watch APl时,apiserver在response的HTTP Header中设置Transfer-Encoding的值为chunked,表示采用分块传输编码,客户端收到该信息后,便和服务端该链接,并等待下一个数据块,即资源的事件信息,直到客户主动断链。

 

List-Watch的设计理念

一个异步消息的系统时,对消息机制有至少如下四点要求

消息可靠性:

首先消息必须是可靠的,list和watch一起保证了消息的可靠性,避免因消息丢失而造成状态不一致场景。具体而言,list APY可以查询当前的资源及其对应的状态(即期望的状态),客户端通过拿期望的状态和实际的状态进行对比,纠正状态不一致的资源。Watch API和apiserver保持一个长链接,接收资源的状态变更事件并做相应处理。如果仅调用watch API,若某个时间点连接中断,就有可能导致消息丢失,所以需要通过list API解决消息丢失的问题。从另一个角度出发,我们可以认为list API获取全量数据,watch API获取增量数据。虽然仅仅通过轮询list API,也能达到同步资源状态的效果,但是存在开销大,实时性不足的问题。

消息实时性

消息必须是实时的,list-watch机制下,每当apiserver的资源产生状态变更事件,都会将事件及时的推送给客户端,从而保证了消息的实时性。

消息顺序性

消息的顺序性也是非常重要的,在并发的场景下,客户端在短时间内可能会收到同一个资源的多个事件,对于关注最终一致性的K8S来说,它需要知道哪个是最近发生的事件,并保证资源的最终状态如同最近事件所表述的状态一样。K8S在每个资源的事件中都带一个resourceVersion的标签,这个标签是递增的数字,所以当客户端并发处理同一个资源的事件时,它就可以对比resourceVersion来保证最终的状态和最新的事件所期望的状态保持一致。

高性能

List-watch还具有高性能的特点,虽然仅通过周期性调用list API也能达到资源最终一致性的效果,但是周期性频繁的轮询大大的增大了开销,增加apiserver的压力。

而watch作为异步消息通知机制,复用一条长链接,保证实时性的同时也保证了性能。

 

list-watch 实现机制

List-watch的API处理, kube-apiserver API注册代码pkg/apiserver/api_installer.go

1.rest.Storage对象会被转换为watcher和lister对象

2.提供list和watch服务的入口是同一个,在API接口中通过GET /xxx/services?watch=ture来区分

3. API处理函数是统一通过ListResource完成

list-watch 实现机制

ListResource()的具体实现

每次有一个watch的url请求过来,都会调用rw.Watch()创建一个watcher,然后使用serveWatch()来处理这个请求。watcher的生命周期是每个http请求的,这一点非常重要。

list-watch 实现机制

响应http请求的过程serveWatch()的代码在/pkg/apiserver/watch.go里面

watcher的结果channel中读取一个event对象,然后持续不断的编码写入到http response的流当中。

 

...全文
805 回复 打赏 收藏 举报
写回复
回复
切换为时间正序
请发表友善的回复…
发表回复
相关推荐
发帖
Gauss松鼠会
加入

1.9w+

社区成员

汇集数据库的爱好者和关注者,大家共同学习、探索、分享数据库前沿知识和技术,像松鼠一样剥开科学的坚果;交流Gauss及其他数据库的使用心得和经验,互助解决问题,共建数据库技术交流圈。
社区管理员
  • Gauss松鼠会
帖子事件
创建了帖子
2022-05-09 19:56
社区公告

欢迎大家同时关注Gauss松鼠会专家酷哥。

https://www.zhihu.com/people/ku-ge-78-98