概述

在上一篇关于 CRD 的 Typed Client 的使用实操中,因为内容相对比较多,所有有一些比较关键的点被一笔带过了,或者我认为不适合放在一起讲,所以就忽略了,所以在这一篇中,我决定补一下漏,对一些我觉得比较重要的概念补充说明一下。

clientset

在上一篇关于 CRD 的 Typed Client 的使用实操中,我快速得提了一口 clientset,但是,并没有详细地介绍一下什么是 clientset,但是我认为那一句也算是概要得说完了 clientset 的含义:可以以 Typed Client 和 API Server 交互的 Client,这里就对 clientset 进行更多的介绍。

在 Typed Client 中,clientset 的意思其实就是 client 的集合,也就是说内部包含了很多 client,例如看下 Client-Go 中的 clientset 还有我自己生成的 clientset:

从这里的注释中可以看到,clientset 中的 client 是以 GV 为单位的,每个 GV 就是一个 client,然后不同的 version 就会发现不同的 client;同时,对比一下 Client Go 中的和我自己生成的,可以看到,都包含了 discovery.DiscoveryClient,不过一般用不着,比较常被 RESTMappers 和命令行工具使用。

OK,这就是关于 clientset 的更多解释了,无需太多理解,就是 client 的 set。

Informer

当拥有了 SDK 用于操作 Kubernetes 的资源的时候,每个请求都打到 Kubernetes 的 API Server 似乎会让 Api Server 组件成为 Kubernetes 系统的性能瓶颈;事实上,在实际使用中,对于 Resource 的查询请求远多于其他操作,所以为了缓解 API Server 的压力,Kubernetes 引入了一个 Informer 的组件。

Informer 的作用就是,监听 API Server 的资源变动事件,然后根据事件在本地缓存 Kubernetes 的资源信息(内部有个 Cache),然后 Client 关于 Kubernetes 资源的查询都从 Informer 上来,同时,Informer 也会同步得将 Client 关注的事件传回给 Client,就像这样:

Event

在 Kubernetes 中,除了允许主动向 API Server 请求操作资源之外,还可以订阅 API Server 中资源的变化(得益于 etcd 的 watch 机制),从而可以让代码更加得高效。想订阅指定的资源,可以通过 clientset 中的 Watch 接口:

当调用成功之后,会返回一个 Interface,内部包含一个 Channel 和 Stop 方法,可以通过 Channel 获取变更的资源信息。这里需要关注的是,因为 Watch 是长连接,所以可能会出现中间断连的情况,同时,也可能会因为 API Server 的状态调整导致 Event 的一些异常情况,所以,Informer 做的不仅仅是 Watch 这么简单,它还包含了连接管理以及定时 List 用于弥补可能存在的 Event 缺失。

注意点

千万不要修改从 Informer 获取的资源对象,一旦这么做了,那么就可能导致对象的状态错乱,引发难以调试的状态错误。正确的操作方法是 deepcopy 一份,deepcopy 也是我在第三篇中代码自动生成时说过开始可能 register.go 会报错,但是,生成代码之后就不会的那个关键组件。

Work Queue

在 Client Go 中,后面我们还会经常遇到的一个数据结构就是 Work Queue,因为前面的 Event 机制对于资源的通知是一次性的,如果收到通知的那个时刻应用不是太方便处理或者处理过程因为非永久性的异常导致不能即时消化,那么就有必要进行一些重试的机制,所以,Client Go 中有了 Work Queue。

Work Queue 其实就一个 Queue,接口为:

  1. type Interface interface {
  2. Add(item interface{})
  3. Len() int
  4. Get() (item interface{}, shutdown bool)
  5. Done(item interface{})
  6. ShutDown()
  7. ShuttingDown() bool
  8. }

这只是一个接口,然后,还有两个实现:

这两个接口会在我们后面的实战中出现,所以可以先有个概念,留意一下。

Ref