Kubernetes list-watch 原理和源码

536 阅读1分钟

概述

以C/S的视角看,List-Watch发生在2个地方,一个是client-go中,一个在api-server中。

  • client-go向api-server发起list和watch请求,通信方式是HTTP2的chunk模式
  • api-server向etcd发起list和watch,将数据缓存在内存的一个环形数组中,resourceVersion从小到大有序

细节

源码索引

client-go: reflector

client-go中负责向api-server发起list-watch的核心组件是reflector,我们可以找到它的定义: staging/src/k8s.io/client-go/tools/cache/reflector.go

type Reflector struct {
    listerWatcher ListerWatcher
}

// ListAndWatch first lists all items and get the resource version at the moment of call,
// and then use the resource version to watch.
func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
    pager := pager.New(pager.SimplePageFunc(func(opts metav1.ListOptions) (runtime.Object, error) {
            return r.listerWatcher.List(opts)
    }))
    
    w, err := r.listerWatcher.Watch(options)
}

暂且不管listerWatcher是如何实现的,可以从源码中精准地判断list和watch是2个不同的操作。

informerFactory: options

NewSharedInformerFactoryWithOptions 方法让用户可以传递ListOptions,那么这个Options是如何其作用的呢,以PodInformer为例。

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
}

type podInformer struct {
	factory          internalinterfaces.SharedInformerFactory
	tweakListOptions internalinterfaces.TweakListOptionsFunc
	namespace        string
}

func (f *podInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
	return NewFilteredPodInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}

func NewFilteredPodInformer(client kubernetes.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
	return cache.NewSharedIndexInformer(
		&cache.ListWatch{
			ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
				if tweakListOptions != nil {
					tweakListOptions(&options)
				}
				return client.CoreV1().Pods(namespace).List(context.TODO(), options)
			},
			WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
				if tweakListOptions != nil {
					tweakListOptions(&options)
				}
				return client.CoreV1().Pods(namespace).Watch(context.TODO(), options)
			},
		},
		&corev1.Pod{},
		resyncPeriod,
		indexers,
	)
}

api-server: watchCache

watchCache 是缓存对象的环形缓冲区

type watchCache struct {
    cache      []*watchCacheEvent
    startIndex int
    endIndex   int
}

func (w *watchCache) updateCache(event *watchCacheEvent) {
	w.resizeCacheLocked(event.RecordTime)
	if w.isCacheFullLocked() {
		// Cache is full - remove the oldest element.
		w.startIndex++
	}
	w.cache[w.endIndex%w.capacity] = event
	w.endIndex++
}
// Creates a cacher based given storageConfig.
func StorageWithCacher() generic.StorageDecorator {
}

func NewCacherFromConfig(config Config) (*Cacher, error) {
}

参考

blog.csdn.net/Matthew__M/… developer.aliyun.com/article/939… zhuanlan.zhihu.com/p/59660536 zhuanlan.zhihu.com/p/33335726