Understanding the Informer Mechanism in Kubernetes client-go

The Informer mechanism in Kubernetes’ client-go library enables efficient caching and event-driven processing of API resources. It abstracts away low-level details like listing, watching, and reconciling resource state, allowing controllers to react to changes without polling the API server directly.

SharedInformerFactory

SharedInformerFactory acts as a central registry for creating shared informers across all supported API groups and versions. Each informer instance is cached per resource type, ensuring only one watch connection exists per resource—even when multiple controllers need the same data.

type SharedInformerFactory interface {
	ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
	WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
	Core() core.Interface
	Apps() apps.Interface
	// ... other API group accessors
}

Calling methods like Apps().V1().Deployments() returns a typed informer:

type DeploymentInformer interface {
	Informer() cache.SharedIndexInformer
	Lister() v1.DeploymentLister
}

This design separates concerns: the informer handles event propagation, while the lister provides read access to the local cache.

SharedIndexInformer Internals

At its core, SharedIndexInformer coordinates four key components:

  • Indexer: A thread-safe store with support for secondary indexes.
  • Reflector: Watches the API server and reflects changes into a DeltaFIFO queue.
  • Controller: Drives the reflector and porcesses deltas from the queue.
  • Processor: Distributes events to registered handlers.

Reflector and DeltaFIFO

The Reflector uses a ListerWatcher to perform an initial list and then establish a persistent watch. All observed changes are pushed into a DeltaFIFO, which tracks object transitions (add, update, delete) as "deltas."

fifo := NewDeltaFIFO(MetaNamespaceKeyFunc, indexer)
r := NewReflector(lw, objType, fifo, resyncPeriod)

The DeltaFIFO uses the Indexer as its knownObjects, enabling correct handling of deletions and resyncs by referencing the current local state.

Event Processing Pipeline

When the controller processes a delta from the FIFO, it updates the Indexer and forwards notifications to listeners:

func (s *sharedIndexInformer) HandleDeltas(obj interface{}) error {
	for _, d := range obj.(Deltas) {
		switch d.Type {
		case Added, Updated:
			// Update indexer
			s.indexer.Add(d.Object) // or Update
			// Notify listeners
			s.processor.distribute(addNotification{newObj: d.Object}, isSync)
		case Deleted:
			s.indexer.Delete(d.Object)
			s.processor.distribute(deleteNotification{oldObj: d.Object}, false)
		}
	}
	return nil
}

Each registered ResourceEventHandler is wrapped in a processorListener. Notiifcations are sent over a buffered channel (addCh) and then relayed to a consumption channel (nextCh) via a pop() goroutine that manages backpressure and batching.

The run() method of each listener consumes from nextCh and invokes the appropriate handler method:

for next := range p.nextCh {
	switch n := next.(type) {
	case addNotification:
		p.handler.OnAdd(n.newObj)
	case updateNotification:
		p.handler.OnUpdate(n.oldObj, n.newObj)
	case deleteNotification:
		p.handler.OnDelete(n.oldObj)
	}
}

This decoupling ensures that slow handlers don’t block the main event distribution pipeline.

ListerWatcher Abstraction

The ListerWatcher interface encapsulates the logic for listing and watching a specific resource:

type ListerWatcher interface {
	List(opts metav1.ListOptions) (runtime.Object, error)
	Watch(opts metav1.ListOptions) (watch.Interface, error)
}

In practice, this is implemented using the Kubernetes clientset:

&cache.ListWatch{
	ListFunc: func(opts metav1.ListOptions) (runtime.Object, error) {
		return client.AppsV1().Deployments(ns).List(ctx, opts)
	},
	WatchFunc: func(opts metav1.ListOptions) (watch.Interface, error) {
		return client.AppsV1().Deployments(ns).Watch(ctx, opts)
	},
}

This bridges the informer to the actual API server endpoints while allowing customization (e.g., label selectors via TweakListOptions).

Tags: kubernetes client-go Informer Controller source-code-analysis

Posted on Tue, 11 Aug 2026 16:09:07 +0000 by maciek4