watch.Interface vs. cache.NewInformer vs. cache.NewSharedIndexInformer?
Asked Answered
N

1

34

I need my Go app to monitor some resources in a Kubernetes cluster and react to their changes. Based on numerous articles and examples, I seem to have found a few ways to do it; however, I'm unable to grasp the difference between them — and thus, to know which one to use, so that I don't get some unexpected behaviors. Specifically:

  1. watch.Interface.ResultChan() — (acquired through e.g. rest.Request.Watch()) — this already seems to let me react to changes happening to a resource, by providing Added/Modified/Deleted events;

  2. cache.NewInformer() — when I implement a cache.ResourceEventHandler, I can pass it as last argument in:

    cache.NewInformer(
            cache.NewListWatchFromClient(clientset.Batch().RESTClient(), "jobs", ...),
            &batchv1.Job{},
            0,
            myHandler)
    

    then, the myHandler object will receive OnAdd()/OnUpdate()/OnDelete() calls.

    To me, this seems more or less equivalent to the ResultChan I got in (1.) above; one difference is that apparently now I get the "before" state of the resource as a bonus, whereas with ResultChan I would only get its "after" state.

    Also, IIUC, this is actually somehow built on the watch.Interface mentioned above (through NewListWatchFromClient) — so I guess it brings some value over it, and/or fixes some (what?) deficiencies of a raw watch.Interface?

  3. cache.NewSharedInformer() and cache.NewSharedIndexInformer() — I tried to dig through the godocs, but I feel completely overloaded with terminology I don't understand, such that I don't seem to be able to grasp the differences between a "regular" NewInformer vs. NewSharedInformer vs. NewSharedIndexInformer.

What are the differences between above APIs in the Kubernetes client-go package?

Nacred answered 31/12, 2019 at 12:25 Comment(0)
K
37

These methods differ in the level of abstraction. If a higher level abstraction fits your need, you should use it, as many lower level problems is solved for you.

Informers is a higher level of abstraction than watch that also include listers. In most use cases you should use any kind of Informer instead of lower level abstraction. An Informer internally consists of a watcher, a lister and an in-memory cache.

SharedInformers share the connection with the API server and other resources between your informers.

SharedIndexInformers add an index to your data cache, in case you work with a larger dataset.

It is recommended to use SharedInformers instead of the lower level abstractions. Instantiate new SharedInformes from the same SharedInformerFactory. Theres is an example in Kubernetes Handbook example

informerFactory := informers.NewSharedInformerFactory(clientset, time.Second*30)

podInformer := informerFactory.Core().V1().Pods()
serviceInformer := informerFactory.Core().V1().Services()

podInformer.Informer().AddEventHandler(
    // add your event handling 
)

// add event handling for serviceInformer

informerFactory.Start(wait.NeverStop)
informerFactory.WaitForCacheSync(wait.NeverStop)
Katabolism answered 31/12, 2019 at 13:15 Comment(7)
What lower level problems? — I don't seem to see any with Watcher, and I am specifically anxious what I might be missing? Also, does the "in-memory cache" help me in any way if I'm just listening to resource change events? Finally, does the connection sharing happen "magically" through client-go's internal global vars, or do I have to arrange for this somehow, e.g. by ensuring they're built from the same ListerWatcher, or something else? As to index = for larger dataset, this seems to clear that aspect up, thanks!!!Nacred
@Nacred by just using watch, you may miss events (e.g. network problems) sometimes and it can be solved by regularly do a list request... all this is handled for you with Informers. Yes, sharedInformers will be shared automatically, but you need to use the same sharedInformerFactory to instantiate them.Katabolism
so, if I just run NewSharedInformer, it will not be shared with anything, unless I get hold of some preexisting SharedInformerFactory? What's the point of this func then? If I don't have access to a factory, I can just create a non-shared NewInformer and it will be no different?Nacred
@Nacred those are building blocks that the factory will call. See my code example on how to use SharedInformerFactory and it has fewer parameters, fewer technical details that the developer need to think about - higher abstractions.Katabolism
Thanks; your answer is definitely helpful; though you skipped answering some of the clarification questions I posed, which leaves me still with a lot of doubts, so I'm not ready to mark this as the Accepted Answer in its current state.Nacred
This should be the intro to the java library also, which is absolutely terribly described. Thank u for the answer.Nodose
I also have the same doubts. Can any of you please clarify if possible?Plunger

© 2022 - 2024 — McMap. All rights reserved.