图解 K8S 源码 - Informer 篇

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 图解 K8S 源码中的 Informer 机制及 Reflector 实现。

前言

众所周知,在 Kubernetes 中各组件是通过 HTTP 协议进行通信的,而组件间的通信也并没有依赖任何中间件,那么如何保证消息的实时性、可靠性、顺序性呢?Informer 机制很好的解决了这个问题。Kubernetes 中各组件与 API Server 的通信都是通过 client-go 的 informer 机制来保证和完成的。

控制器模式

控制器模式最核心的就是控制循环的概念。而 Informer 机制,也就是控制循环中负责观察系统的传感器(Sensor)主要由 Reflector、Informer、Indexer 三个组件构成。其与各种资源的 Controller 相配合,就可以完成完整的控制循环,不断的使系统向终态趋近 status -> spec

informer 机制

Informer

所谓 informer,其实就是一个带有本地缓存和索引机制的,可以注册 EventHandler 的 client,目的是为了减轻频繁通信 API Server 的压力而抽取出来的一层 cache,客户端对 API Server 数据的读取监测操作都通过本地的 informer 来进行。

每一个 Kubernetes 资源上都实现了 informer 机制,每一个 informer 上都会实现 Informer()Lister() 方法:

// client-go/informers/core/v1/pod.go
type PodInformer interface {
  Informer() cache.SharedIndexInformer
  Lister() v1.PodLister
}

定义不同资源的 Informer,允许监控不同资源事件。同时为了避免同一资源的 Informer 被实例化多次,而每个 Informer 都会使用一个 Reflector,这样会运行过多相同的 ListAndWatch,从而加重 API Server 的压力,Informer 还提供了共享机制,多个 Informer 可以共享一个 Reflector,从而达到节约资源的目的。

// client-go/informers/factory.go
type sharedInformerFactory struct {
  client           kubernetes.Interface
  namespace        string
  tweakListOptions internalinterfaces.TweakListOptionsFunc
  lock             sync.Mutex
  defaultResync    time.Duration
  customResync     map[reflect.Type]time.Duration

  informers map[reflect.Type]cache.SharedIndexInformer
  // startedInformers is used for tracking which informers have been started.
  // This allows Start() to be called multiple times safely.
  startedInformers map[reflect.Type]bool
}
...
// InternalInformerFor returns the SharedIndexInformer for obj using an internal client.
func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
  f.lock.Lock()
  defer f.lock.Unlock()

  informerType := reflect.TypeOf(obj)
  informer, exists := f.informers[informerType]
  if exists {
    return informer
  }

  resyncPeriod, exists := f.customResync[informerType]
  if !exists {
    resyncPeriod = f.defaultResync
  }

  informer = newFunc(f.client, resyncPeriod)
  f.informers[informerType] = informer

  return informer
}

使用 map 数据结构实现共享 Informer 机制,在 InformerFor() 函数添加了不同资源的 Informer,在添加过程中如果已经存在同类型的 Informer,则返回当前 Informer,不再继续添加。如下就是 deploymentInformer() 方法,其中就调用了 InformerFor() 函数。

// client-go/informers/apps/v1beta1/deployment.go
func (f *deploymentInformer) Informer() cache.SharedIndexInformer {
  return f.factory.InformerFor(&appsv1beta1.Deployment{}, f.defaultInformer)
}

Reflector

Reflector 用于监测制定 Kubernetes 资源,当资源发生变化时,触发相应的事件,如:Added(资源添加)事件、Update(资源更新)事件、Delete(资源删除)事件,并将事件及资源名称添加到 DeltaFIFO 中。

ListAndWatch

在实例化 Reflector 时,必须传入 ListerWatcher 接口对象,其拥有 List()Watch() 方法。Reflector 通过 Run() 方法启动监控并处理事件。在程序第一次运行时,会执行 List() 方法将所有的对象数据存入 DeltaFIFO 中,每次 Controller 重启,都会执行 List() 方法;同时,Reflector 实例中还有 resyncPeriod 参数,如果该参数不为 0,则会根据该参数值周期性的执行 List() 操作,此时这些资源对象会被设置为 Sync 操作类型(不同于 Add、Update 等)。

Watch() 则会根据 Reflector 实例 period 参数,周期性的监控资源对象是否有变更。如果发生变更,则通过 r.watchHandler 处理变更事件。

Reflector

DeltaFIFO

DeltaFIFO 顾名思义,Delta 是一个资源对象存储,可以保持操作类型(Add、Update、Delete、Sync等);而 FIFO 则是一个先进先出的队列。其是一个生产者与消费者的队列,其中 Reflector 是生产者,消费者则调用 Pop() 方法取出最早进入队列的对象数据。

Indexer

Indexer 是 client-go 用来存储资源对象并自带索引功能的本地存储,Reflector 从 DeltaFIFO 中将消费出来的资源对象存储至 Indexer。同时 Indexer 中的数据与 Etcd 中的数据保持完全一致。client-go 可以很方便的从本次存储中读取相应的资源对象数据,而无需每次都从远程 Etcd 集群中读取,从而降低了 API Server 和 Etcd 集群的压力。

结语

要了解 Kubernetes,Informer 是绕不过的内容,其在 Kubernetes 中非常重要。本文主要图解了 Informer 机制以及 Reflector,由于篇幅有限,DeltaFIFO,Indexer 等概念只做了简单介绍,这些内容会在后续的文章中进行详解,敬请期待。

欢迎扫描二维码关注公众号,了解更多云原生知识

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
Kubernetes 应用服务中间件 nginx
|
Kubernetes 算法 调度
|
存储 Kubernetes 安全
【K8s源码品读】010:Phase 1 - kube-scheduler - Informer是如何保存数据的
了解Informer在发现资源变化后,是怎么处理的
61 0
|
Kubernetes 容器
【K8s源码品读】009:Phase 1 - kube-scheduler - Informer监听资源变化
了解Informer是如何从kube-apiserver监听资源变化的情况
111 0
|
存储 Kubernetes API
【K8s源码品读】007:Phase 1 - kube-apiserver - Pod数据的保存
理解Pod发送到kube-apiserver后是怎么保存的
66 0
|
Kubernetes API 网络架构
【K8s源码品读】006:Phase 1 - kube-apiserver - GenericAPIServer的初始化
理解kube-apiserver是中的管理核心资源的KubeAPIServer是怎么启动的
60 0
|
Kubernetes 容器
【K8s源码品读】005:Phase 1 - kube-apiserver 权限相关的三个核心概念
理解启动kube-apiserver的权限相关的三个核心概念 Authentication/Authorization/Admission
57 0
|
设计模式 Kubernetes 网络架构
下一篇
无影云桌面