Introduction to Fabric8 Kubernetes Java Client Informer API

Rohan Kumar
4 min readMay 10, 2020

--

Fabric8 Kubernetes Java Client
Fabric8 Kubernetes Java Client

Introduction:

There are various occasions when you want to monitor some resources in a Kubernetes cluster and react to their changes. In most of the cases, you can do a simple watch and handle events based on their respective type. For example, in order to watch Pod resource. You could simply do:

Watching all Pods in `default` namespace: PodWatch.java

This is just going to initiate a list REST API request with watch=true query parameter appended. It should work for most of the cases and you should not have much problems with it when used for short term. However, when you’re writing high level applications (like Kubernetes Operators) you might want something with higher level of abstraction. An operator that accesses the Kubernetes API server everytime it needs an object creates heavy load on the system. This is where Kubernetes Client Informers come into picture.

What’s the benefit of using Informers over plain Watch?

  • You are more prone to miss events (e.g. network problems) sometimes during plain Watch. But Informers take care of all these low level problems as they include as internally it consists of a watcher, a lister and an in-memory cache.
  • Informers use the Kubernetes API to learn about changes in the state of a Kubernetes cluster and use that information to maintain a cache (the indexer) of the current cluster state and to inform clients about the changes by calling handler functions. This cache can be used for quick lookup thereby reducing load on Kubernetes API server.
  • Informers also allow you to add index to your client side data cache, in case you work with larger clusters with large datasets.
  • Informers also have advanced recovery strategy for handling failures: when long running watch connections get terminated due to API server restart and users start getting HTTP_GONE errors because those events are no longer in etcd anymore. In this scenario, informer would not crash and would relist all objects.

Using Informers with Fabric8 Kubernetes Client:

To use Informers in Fabric8 Kubernetes Client, you either need to access SharedInformerFactory or create a single informer using inform() DSL.

Using SharedInformerFactory, You can do it by simply doing:

SharedInformerFactory sharedInformerFactory = client.informers();

Once SharedInformerFactory has been initialized, you can create a SharedIndexInformer for some resource like this:

SharedIndexInformer<Pod> podInformer = sharedInformerFactory.sharedIndexInformerFor(
Pod.class, // POJO for Pod resource
30 * 1000L); // resync period (set 0 for no resync)

I think first two arguments for sharedIndexInformerForare self-explanatory. Third argument is resync period, it tells the informer to rebuild its cache every 30 seconds. What to set as resync period depends on context, typically it’s set in minutes but it may vary depending on situation. If you don’t want any resync, just set this to 0.

Using inform() DSL method, a single informer can be created like this (the main difference in this approach vs the factory approach is that the created informer would be automatically started, user would need to manage SharedIndexInformer object lifecycle or use try-with-resources):

SharedIndexInformer<Job> jobInformer = client.batch().v1().jobs()
.inNamespace("default")
.inform(new ResourceEventHandler<>() {
@Override
public void onAdd(Job job) { }

@Override
public void onUpdate(Job oldJob, Job newJob) { }

@Override
public void onDelete(Job job, boolean deletedFinalUnknown) { }
}, 30 * 1000L); // resync period (set 0 for no resync)

If we want to do a plain watch like we did in the beginning but using SharedInformerFactory Informers. We would do it in a way like this:

Watching all Pods in all namespaces using Informers: InformerDemo.java

When you run this code, you would be able to see that you’re getting events for all the pods in all namespaces in your cluster:

Watching all Pods in all namespaces: InformerDemo.java

In case you want to use Informer API for some CustomResource, you can do it in a similar way. You just need to provide an additional object as an argument which will provide basic details of your CustomResource . Here is an example:

Informer API usage for CustomResources: CustomResourceInformerDemo.java

When you run this code, you can see all the notifications related to CronTab Custom Resource objects:

Running CustomResourceInformerDemo.java

Using Namespaced Informers:

You can also use Informer specific to one namespace. We have introduced a DSL inform()method in order to handle filtered SharedIndexInformer objects. Here is an example which demonstrates watching for changes inside the default namespace:

Using Namespaced Informers: NamespacedInformerDemo.java

Handling Errors:

There can be some unexpected errors while informer work flow. If they are errors during SharedIndexInformer initialization, it can be caught if you call startedFuture.get() on informerFactory.startAllRegisteredInformers() . SharedInformerFactory also has a method to register event listeners to catch exceptions:

Handling Exception while working with Informers

I would recommend using Informers for writing Kubernetes Operations rather than using just plain list and watch. I wrote a very simple Kubernetes Operators using this Informer API last year. You can check it out for getting more information on how to write operators using this API:

I hope this short blog was able to provide a brief overview of Fabric8 Kubernetes Client’s Informer API. If you face any problems with it, feel free to file an issue on our Github. If you like Fabric8 Kubernetes Client, please support our project by starring 🌟 it on Github.

If you want to get involved in the project development, please checkout CONTRIBUTIONS.md. We ❤️ contributions!

--

--