k8s client-go源码分析 informer源码分析(1)-概要分析
k8s informer概述
我们都知道可以使用k8s的Clientset来获取所有的原生资源对象,那么怎么能持续的获取集群的所有资源对象,或监听集群的资源对象数据的变化呢?这里不需要轮询去不断执行List操作,而是调用Watch接口,即可监听资源对象的变化,当资源对象发生变化,客户端即可通过Watch接口收到资源对象的变化。
Watch接口虽然可以直接使用,但一般情况下很少直接使用,因为往往由于集群中的资源较多,我们需要自己在客户端去维护一套缓存,而这个维护成本比较大。
也是因为如此,client-go提供了自己的实现机制,Informers应运而生。informers实现了持续获取集群的所有资源对象、监听集群的资源对象变化功能,并在本地维护了全量资源对象的内存缓存,以减少对apiserver、对etcd的请求压力。Informers在启动的时候会首先在客户端调用List接口来获取全量的对象集合,然后通过Watch接口来获取增量的对象,然后更新本地缓存。
此外informers也有很强的健壮性,当长期运行的watch连接中断时,informers会尝试拉起一个新的watch请求来恢复连接,在不丢失任何事件的情况下恢复事件流。另外,informers还可以配置一个重新同步的周期参数,每间隔该周期,informers就会重新List全量数据。
在informers的使用上,通常每个GroupVersionResource(GVR)只实例化一个informers,但有时候我们在一个应用中往往会在多个地方对同一种资源对象都有informer的需求,所以就有了共享informer,即SharedInformerFactory。所以可以通过使用SharedInformerFactory来实例化informers,这样本地内存缓存就只有一份,通知机制也只有一套,大大提高了效率,减少了资源浪费。
k8s informer架构

k8s client-go informer主要包括以下部件:
(1)Reflector:Reflector从kube-apiserver中list&watch资源对象,然后调用DeltaFIFO的Add/Update/Delete/Replace方法将资源对象及其变化包装成Delta并将其丢到DeltaFIFO中;
(2)DeltaFIFO:DeltaFIFO中存储着一个map和一个queue,即map[object key]Deltas以及object key的queue,Deltas为Delta的切片类型,Delta装有对象及对象的变化类型(Added/Updated/Deleted/Sync) ,Reflector负责DeltaFIFO的输入,Controller负责处理DeltaFIFO的输出;
(3)Controller:Controller从DeltaFIFO的queue中pop一个object key出来,并获取其关联的 Deltas出来进行处理,遍历Deltas,根据对象的变化更新Indexer中的本地内存缓存,并通知Processor,相关对象有变化事件发生;
(4)Processor:Processor根据对象的变化事件类型,调用相应的ResourceEventHandler来处理对象的变化;
(5)Indexer:Indexer中有informer维护的指定资源对象的相对于etcd数据的一份本地内存缓存,可通过该缓存获取资源对象,以减少对apiserver、对etcd的请求压力;
(6)ResourceEventHandler:用户根据自身处理逻辑需要,注册自定义的的ResourceEventHandler,当对象发生变化时,将触发调用对应类型的ResourceEventHandler来做处理。
根据informer架构,对k8s informer的分析将分为以下几部分进行,本篇为概要分析:
(1)informer概要分析;
(2)informer之初始化与启动分析;
(3)informer之Reflector分析;
(4)informer之DeltaFIFO分析;
(5)informer之Controller&Processor分析;
(6)informer之Indexer分析;
informer使用示例代码
使用大致过程如下:
(1)构建与kube-apiserver通信的config配置;
(2)初始化与apiserver通信的clientset;
(3)利用clientset初始化shared informer factory以及pod informer;
(4)注册informer的自定义ResourceEventHandler;
(5)启动shared informer factory,开始informer的list & watch操作;
(6)等待informer从kube-apiserver同步资源完成,即informer的list操作获取的对象都存入到informer中的indexer本地缓存中;
(7)创建lister,可以从informer中的indexer本地缓存中获取对象;
func main() {
// 自定义与kube-apiserver通信的config配置
master := "192.168.1.10" // apiserver url
kubeconfig := "/.kube/config"
config, err = clientcmd.BuildConfigFromFlags(master, kubeconfig)
if err != nil {
klog.Fatalf("Failed to create config: %v", err)
}
// 或使用k8s serviceAccount机制与kube-apiserver通信
// config, err = rest.InClusterConfig()
// 初始化与apiserver通信的clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
klog.Fatalf("Failed to create client: %v", err)
}
// 初始化shared informer factory以及pod informer
factory := informers.NewSharedInformerFactory(clientset, 30*time.Second)
podInformer := factory.Core().V1().Pods()
informer := podInformer.Informer()
// 注册informer的自定义ResourceEventHandler
informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
AddFunc: xxx,
UpdateFunc: xxx,
DeleteFunc: xxx,
})
// 启动shared informer factory,开始informer的list & watch操作
stopper := make(chan struct{})
go factory.Start(stopper)
// 等待informer从kube-apiserver同步资源完成,即informer的list操作获取的对象都存入到informer中的indexer本地缓存中
// 或者调用factory.WaitForCacheSync(stopper)
if !cache.WaitForCacheSync(stopper, informer.HasSynced) {
runtime.HandleError(fmt.Errorf("Timed out waiting for caches to sync"))
return
}
// 创建lister
podLister := podInformer.Lister()
// 从informer中的indexer本地缓存中获取对象
podList, err := podLister.List(labels.Everything())
if err != nil {
fmt.Println(err)
}
}
总结
以上只是对K8s informer做了简单的介绍,以及简单的写了一下如何使用informer的示例代码,后面将开始对informer的各个部件做进一步的源码分析,敬请期待。
最后以一张k8s informer的架构图作为结尾总结,大家回忆一下k8s informer的架构组成以及各个部件的作用。

k8s client-go源码分析 informer源码分析(1)-概要分析的更多相关文章
- k8s client-go源码分析 informer源码分析(2)-初始化与启动分析
k8s client-go源码分析 informer源码分析(2)-初始化与启动分析 前面一篇文章对k8s informer做了概要分析,本篇文章将对informer的初始化与启动进行分析. info ...
- k8s client-go源码分析 informer源码分析(3)-Reflector源码分析
k8s client-go源码分析 informer源码分析(3)-Reflector源码分析 1.Reflector概述 Reflector从kube-apiserver中list&watc ...
- k8s client-go源码分析 informer源码分析(4)-DeltaFIFO源码分析
client-go之DeltaFIFO源码分析 1.DeltaFIFO概述 先从名字上来看,DeltaFIFO,首先它是一个FIFO,也就是一个先进先出的队列,而Delta代表变化的资源对象,其包含资 ...
- k8s client-go源码分析 informer源码分析(5)-Controller&Processor源码分析
client-go之Controller&Processor源码分析 1.controller与Processor概述 Controller Controller从DeltaFIFO中pop ...
- k8s client-go源码分析 informer源码分析(6)-Indexer源码分析
client-go之Indexer源码分析 1.Indexer概述 Indexer中有informer维护的指定资源对象的相对于etcd数据的一份本地内存缓存,可通过该缓存获取资源对象,以减少对api ...
- Kubernetes client-go Informer 源码分析
概述ControllerController 的初始化Controller 的启动processLoopHandleDeltas()SharedIndexInformersharedIndexerIn ...
- kube-scheduler源码分析(1)-初始化与启动分析
kube-scheduler源码分析(1)-初始化与启动分析 kube-scheduler简介 kube-scheduler组件是kubernetes中的核心组件之一,主要负责pod资源对象的调度工作 ...
- OpenStack源码分析 Neutron源码分析(一)-----------Restful API篇
原文:https://blog.csdn.net/happyanger6/article/details/54586463 首先,先分析WSGI应用的实现. 由前面的文章http://blog.csd ...
- [源码分析] 从源码入手看 Flink Watermark 之传播过程
[源码分析] 从源码入手看 Flink Watermark 之传播过程 0x00 摘要 本文将通过源码分析,带领大家熟悉Flink Watermark 之传播过程,顺便也可以对Flink整体逻辑有一个 ...
随机推荐
- zookeeper 负载均衡和 nginx 负载均衡区别 ?
zk 的负载均衡是可以调控,nginx 只是能调权重,其他需要可控的都需要自己写插件:但是 nginx 的吞吐量比 zk 大很多,应该说按业务选择用哪种方式.
- Zookeeper 下 Server 工作状态?
服务器具有四种状态,分别是 LOOKING.FOLLOWING.LEADING.OBSERVING. 1.LOOKING:寻找 Leader 状态.当服务器处于该状态时,它会认为当前集群中没有 Lea ...
- AOP——基于AspectJ的注解来实现AOP操作
1.使用注解方式实现AOP操作 第一步:创建对象 <!-- 创建对象 --> <bean id="book" class="com.bjxb.aop.B ...
- spring event
昨天看到了一遍关于spring event的帖子,觉得很好,就照着敲了一份代码,感觉对spring event有了进一步的认识.帖子链接:https://segmentfault.com/a/1190 ...
- 学习 Haproxy (二)
1. Haproxy介绍 Haproxy是一个开源的高性能的反向代理或者说是负载均衡服务软件之一,它支持双机热备.虚拟主机.基于TCP和HTTP应用代理等功能.其配置简单,而且拥有很好的对服务器节点的 ...
- USART_GetITStatus()和USART_GetFlagStatus()的区别
USART_GetITStatus()和USART_GetFlagStatus()的区别 都是访问串口的SR状态寄存器,唯一不同是,USART_GetITStatus()会判断中断是否开启,如果没开启 ...
- 付费漫画下载、付费韩漫下载、漫画VIP下载、VIP韩漫下载哪里下
需要的 来qq:6686496 最近迷上了韩漫(你懂的),主要为了打发时间上班摸鱼,,找了好多网站都是要收费的,就想着试着用爬虫做一个破解. 最简单的第一步,通过url分析出漫画ID.(直接看url就 ...
- 面试BAT,你凭什么说你掌握了CSS
介绍 项目已经开源:https://github.com/nanhupatar... 欢迎PR 推荐 关注我们的公众号 display: none; 与 visibility: hidden; 的区别 ...
- 解决canvas画图模糊的问题
canvas 画图经常发现他是模糊的.解决这个问题主要从两个方面下手. 改变canvas渲染的像素情况:画1像素的线条看起来模糊不清,好像更宽的样子. 解决方案 var ctx = canvas.ge ...
- 一个很好用的 vue-picker组件
vue-picker a picker componemt for vue2.0 走了一圈 github 都没有找到自己想要的移动端的 vue-picker的组件,于是自己就下手,撸了一个出来,感受下 ...