client-go代码分析之informer和sharedInformer分析

在茫茫代码中,很容易迷失。经过一段时间的艰苦探索,终于对client-go有了一定的了解,能够从整体上把相关功能串起来。本文主要是informer相关的内容,因为这是client-go比较核心的功能。后面还会发一篇关于client-go编程使用的文章,会从kubernetes.Interface,dynamic,discovery,workequeue和informer工厂函数等方面介绍,再结合一个operator作为实例进行分析(虽然大部分operator都使用kube-builder等类似的工具构建,但是本着求根问底的精神还是要分析一下)。 相关存储结构 在开始介绍之前,先介绍一下client-go中提供存储相关的接口,这些接口用来缓存api对象。Store是最基础的接口,提供增删改查等,还有一些继承于Store的接口,比Store可能会多实现一些方法,可以针对不同的场景进行使用。 Store ExpirationStore UndeltaStore Queue FIFO DeltaFIFO Indexer cache 不同Store的引用 Store接口的具体定义可以看vendor/k8s.io/client-go/tools/cache/store.go这个文件。在IDE的帮助下,找到了所有实现了这个Store的相关实现。本文主要关心client-go,所以主要跟进client-go下面的相关实现。 delta_fifo.go NewDeltaFIFO() NewDeltaFIFOWithOptions() informer和sharedinformer使用到了 vendor/k8s.io/client-go/tools/cache/controller.go:NewInformer() vendor/k8s.io/client-go/tools/cache/shared_informer.go:sharedIndexInformer.Run() expiration_cache.go NewTTLStore() pkg/kubelet/util/cache/object_cache.go:NewObjectCache() NewExpirationStore() pkg/credentialprovider/aws/aws_credentials.go:newECRProvider() pkg/credentialprovider/azure/azure_credentials.go:NewACRProvider() fifo.go 该文件中定义了Queue接口,继承了Store,并且在该文件中通过FIFO实现了这个queue,另外一个实现是在delta_fifo.go中的DeltaFIFO NewFIFO() 代码中未找到该引用 index.go 这个文件定义了Indexer接口,继承了Store,在store.go中通过cache实现了该接口 store.go NewStore() staging/src/k8s.io/client-go/tools/cache/controller.go:NewInformer() staging/src/k8s.io/client-go/tools/cache/undelta_store.go:NewUndeltaStore() NewIndexer() staging/src/k8s.io/apiserver/pkg/storage/cacher/watch_cache.go:newWatchCache() staging/src/k8s.io/client-go/tools/cache/controller.go:NewIndexerInformer() staging/src/k8s.io/client-go/tools/cache/reflector.go:NewNamespaceKeyedIndexerAndReflector() 该函数在IDE中显示未被使用 staging/src/k8s.io/client-go/tools/cache/shared_informer.go:NewSharedIndexInformer() undelata_store.go NewUndeltaStore() pkg/kubelet/config/apiserver.go:newSourceApiserverFromLW() informer简要介绍 client-go中提供了普通informer和sharedInformer两种informer给我们使用。使用informer可以快速的构建各种资源的控制器,来对k8s进行扩展。informer提供了资源变化时执行回调的功能,可以在新增资源,修改资源和是删除资源时执行相应的控制器逻辑。 使用sharedInformer可以对同一个资源注册多个控制器,每个控制器独立执行自己的业务逻辑,互不干扰。多个控制器之间底层公用一个存储和一个到apiserver的连接,可以减少apiserver的压力的和本地内存的占用。informer则不具备这些能力,对于简单控制器可以使用informer,对于较复杂的控制器,会有针对同一个资源多个控制逻辑的推荐使用sharedInformer。 这两个informer在实现的复杂度上有很大差异,sharedInformer相对于普通informer来说要复杂的多。因此本文先从普通informer开始来进行分析,普通informer还分两种,一种是普通的informer,另外一种indexerinfomer。两种informer的区别在于前者使用Store作为对象存储,而后者采用Indexer作为对象存储,通过索引可以加快搜索。 普通informer分析 接下来我们以普通的informer进行分析,关于informer的使用可以参考这里。代码位于k8s.io/client-go/tools/cache/controller.go文件中,该文件中定义了Controller接口,并通过controller进行了实现。 controller分析 先看下接口定义以及controller包含的关键数据结构: // 这两个函数用来创建informer实例 func NewInformer(lw ListerWatcher, objType runtime.Object, resyncPeriod time.Duration, h ResourceEventHandler,) (Store, Controller) {} func NewIndexerInformer(lw ListerWatcher, objType…