client-go informer机制简介

Table of Contents

1. informer机制简介

在Kubernetes系统中,组件之间通过HTTP协议进行通信,在不依赖任何中间件的情况下需要保证消息的实时性、可靠性、顺序性是通过list-watch机制实现的。

作为客户端,client-go也实现了一套对应的list-watch进行用来处理对象的变化。这个机制在client-go就是informer机制。

Kubernetes的其他组件(kcm, kubelet等等)都是通过client-go的Informer机制与Kubernetes API Server进行通信的。

Informer机制运行原理如图:

 

大体流程如下:

(1)new一个informer,然后informer的时候指定了 listAndwatcher(这个就是获取apiserver数据)

(2)informer.Run的时候,会new 一个 Reflector对象。Reflector包含了listAndwatcher,接下来基本就是Reflector进行操作了

(3)Reflector对listWatcher来的数据进行处理,这里使用到了DeltaFIFO队列对watch来的数据一个个的处理,HandleDeltas函数

(4)具体的处理逻辑分为两部分,第一部分是,通过操作cache.indexer,更新本地缓存+索引; 第二部分是,将watch的数据发送给 Informer自定义的处理函数进行处理

本节就先总结一下informer机制的大概流程,然后简单介绍一个流程中出现的几个概念。后面的章节一个一个进行详细研究

1.2. informer机制 example介绍

直接阅读Informer机制代码会比较晦涩,通过Informers Example代码示例来理解Informer,印象会更深刻。Informers Example代码示例如下:

package main
​
import (
  "log"
  "time"
​
  corev1 "k8s.io/api/core/v1"
  "k8s.io/apimachinery/pkg/apis/meta/v1"
  "k8s.io/client-go/informers"
  "k8s.io/client-go/kubernetes"
  "k8s.io/client-go/tools/cache"
  "k8s.io/client-go/tools/clientcmd"
)
​
func main() {
  config, err := clientcmd.BuildConfigFromFlags("", "/root/.kube/config")
  if err!= nil {
    pannic(er)
  }
​
  clientset, err := kubernetes.NewForConfig(config)
    if err!=nil {
      panic(err)
  }
    
  stopCh := make(chan struct{})
  defer close(stopCh)
  sharedInformers := informers.NewSharedInformerFactory(clientset, time.Minute)
  informer := sharedInformers.Core().V1().Pods().Informer()
  
  informers.AddEventHandler(cache.ResourceEventHandlerFuncs{
    AddFunc: func(obj interface{}) {
      mObj := obj.(v1.Object)
      log.Printf("New Pod Added to Store:%s", mObj.GetName())
    },
    UpdateFunc: func(oldObj, newObj interface{}) {
      oObj := oldObj.(v1.Object)
      nObj := newObj.(v1.Object)
      log.Printf("%s Pod Updated to %s", oObj.GetName(), nObj.GetName())
    },
    DeleteFunc: func(obj interface{}) {
      mObj := obj.(v1.Object)
      log.Printf("Pod Deleted from Store:%s", mObj.GetName())
    },
  })
​
  informer.Run(stopCh)
}

首先通过kubernetes.NewForConfig创建clientset对象,Informer需要通过ClientSet与Kubernetes API Server进行交互。另外,创建stopCh对象,该对象用于在程序进程退出之前通知Informer提前退出,因为Informer是一个持久运行的goroutine。informers.NewSharedInformerFactory函数实例化了SharedInformer对象,它接收两个参数:第1个参数clientset是用于与Kubernetes API Server交互的客户端,第2个参数time.Minute用于设置多久进行一次resync(重新同步),resync会周期性地执行List操作,将所有的资源存放在Informer Store中,如果该参数为0,则禁用resync功能。

在Informers Example代码示例中,通过sharedInformers.Core().V1().Pods().Informer可以得到具体Pod资源的informer对象。通过informer.AddEventHandler函数可以为Pod资源添加资源事件回调方法,支持3种资源事件回调方法,分别介绍如下。

● AddFunc:当创建Pod资源对象时触发的事件回调方法。

● UpdateFunc:当更新Pod资源对象时触发的事件回调方法。

● DeleteFunc:当删除Pod资源对象时触发的事件回调方法。在正常的情况下,Kubernetes的其他组件在使用Informer机制时触发资源事件回调方法,将资源对象推送到WorkQueue或其他队列中(实际过程中大都是这样的),在InformersExample代码示例中,我们直接输出触发的资源事件。最后通过informer.Run函数运行当前的Informer,内部为Pod资源类型创建Informer。

2. informer

每一个Kubernetes资源上都实现了Informer机制。每一个Informer上都会实现Informer和Lister方法,例如PodInformer,代码示例如下

// PodInformer provides access to a shared informer and lister for
// Pods.
type PodInformer interface {
  Informer() cache.SharedIndexInformer
  Lister() v1.PodLister
}

用不同资源的Informer,代码示例如下:

podInformer := sharedInformers.Core().V1().Pods().Informer()
nodeInformer := sharedInformers.Node().V1beta1().RuntimeClasses().Informer

定义不同资源的Informer,允许监控不同资源的资源事件,例如,监听Node资源对象,当Kubernetes集群中有新的节点(Node)加入时,client-go能够及时收到资源对象的变更信息。

2.1 shared informer

可以认为 informer都是 shared informer

Informer也被称为Shared Informer,它是可以共享使用的。在用client-go编写代码程序时,若同一资源的Informer被实例化了多次,每个Informer使用一个Reflector,那么会运行过多相同的ListAndWatch,太多重复的序列化和反序列化操作会导致Kubernetes API Server负载过重。Shared Informer可以使同一类资源Informer共享一个Reflector,这样可以节约很多资源。通过map数据结构实现共享的Informer机制。SharedInformer定义了一个map数据结构,用于存放所有Informer的字段,代码示例如下:

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
}

informers字段中存储了资源类型和对应于SharedIndexInformer的映射关系。InformerFor函数添加了不同资源的Informer,在添加过程中如果已经存在同类型的资源Informer,则返回当前Informer,不再继续添加。最后通过Shared Informer的Start方法使f.informers中的每个informer通过goroutine持久运行。

同一个factory定义的shareInformer可以复用复用。

2.2 shared informer是如何实现的

从结构体可以看出来:有一个字段 Store,这里就是保存从apiserver同步过来的数据。

还有一个函数Run(),这个函数会调用controller.Run --> Reflector.Run->ListAndWatch()

而ListAndWatch()就是从apiserver获取数据。

// SharedInformer has a shared data cache and is capable of distributing notifications for changes
// to the cache to multiple listeners who registered via AddEventHandler. If you use this, there is
// one behavior change compared to a standard Informer.  When you receive a notification, the cache
// will be AT LEAST as fresh as the notification, but it MAY be more fresh.  You should NOT depend
// on the contents of the cache exactly matching the notification you've received in handler
// functions.  If there was a create, followed by a delete, the cache may NOT have your item.  This
// has advantages over the broadcaste
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值