ruk·si

Kubernetes
Informer

Updated at 2018-12-31 00:55

Informer is one of the main component of any Kubernetes controller. It watches for changes on the current state and sends events to work queue.

Don't mutate Informer cache objects.

node := store.Get(nodeName)

// bad, if update failes, cache becomes incorrect
node.Annotations["reboot-now"] = "true"
client.Core().Nodes().Update(node)

// good
copyObj := api.Scheme.DeepCopy(node)
nodeCopy := copyObj.(*v1.Node)
delete(nodeCopy.Annotations, "reboot-needed")
client.Core().Nodes().Update(nodeCopy)

Make sure you cache is in sync.

store, controller := cache.NewInformer(...)
controller.Run()

// bad, cache doesn't have time to populate
if len(store.List()) == 0 {
	log.Fatal("no nodes exist")
}
worker.Run()

// good
if !cache.WaitForCacheSync(stopCh, controller.HasSynced) {
	log.Errorf("timeout when waiting for cache to sync")
}
worker.Run()

Use Patch() instead of Update() Update() can remove fields by accident if using old Kubernetes client version.

kubectl taint nodes foo dedicated=special:NoSchedule
// bad, the taints are removed if using Kubernetes client-go 2.0.0
node := nodeStore.Get(nodeName)
node.Annotations["foo"] = "bar"
client.Core().Nodes().Update(node)

// good, updates only changed fields
patch, err = strategicPatch.CreateTwoWayMergePatch(oldObj, newObj, v1.Node{})
client.Core().Nodes().Patch(nodeName, api.StrategicMergePatchType, patch)