Write a simple Kubernetes Operator in Java using the Fabric8 Kubernetes Client

Kubernetes is becoming much more than just a platform for running container workloads. Its API can be extended with application-specific Custom Resource Definitions(CRDs), and you can implement your own logic adapting your applications dynamically to changes in the cluster. In this article, we’ll be writing a simple Kubernetes Operator in Java using the Fabric8 Kubernetes Client.

What is a Kubernetes Operator?

Kubernetes Operators are software extensions to Kubernetes that make use of Custom Resources to manage applications and their components. They let you extend the cluster’s behavior without modifying the code of Kubernetes itself. They are just clients of the Kubernetes API, which act as controllers of that Custom Resource.

In simple terms, a Kubernetes Operator is code that makes use of the Kubernetes API to execute some tasks; Custom Resources act as a configuration model on which that specific code acts.

Everything you need to grow your career. With your free Red Hat Developer program membership, unlock our library of cheat sheets and ebooks on next-generation application development. SIGN UP

Writing a simple PodSet Operator in Java

PodSet Custom Resource

We’ll be writing a very simple operator that tries to do something similar to a ReplicaSet. All the code is hosted on GitHub. It tries to main exactly x amount of pods as with it as a parent. For that, we’ll use a very simple Custom Resource called PodSet . Here is its custom resource definition:

With this Custom Resource Definition applied, A simple PodSet resource can be written as:

Writing Operator

Now let’s jump to writing the operator and have a look at the project structure:

From the structure, we can see three things:

PodSet , PodSetList , PodSetSpec , PodSetStatus , DoneablePodSet as model classes for PodSet custom resources, which are required for deserializing Kubernetes API responses into objects. PodSetOperatorMain , which is the main driver class of the project. PodSetController Class, which contains main Kubernetes logic related to the operator.

Let’s look at each of these in detail.

First, to interact with Kubernetes API in Java, we need the Fabric8 Kubernetes Client. It’s one of the most popular Java APIs for interacting with Kubernetes. We need to add that in pom.xml.

Here is how our pom.xml would look after adding Fabric8 client as a dependency:

Once all the necessary dependencies are added, (which, in our case, is just one 🙂 ), we can then write POJOs, which would be needed by our Java client to create a client for our PodSet custom resource. Here’s how some of them would look after adding them to the project:

PodSet.java

PodSetList.java:

PodSetSpec.java:

Once we have added the model classes, we can go ahead and begin writing our operator. Let’s start with the main driving class (i.e., PodSetOperatorMain ), which would call all the necessary functions in the PodSetController .

First, we need to initialize informers for both Pod resource and PodSet resource, because we’ll be listening to events related to these resources and reacting upon them in our operator. To stay informed about when these events get triggered, we’ll use a primitive exposed by Kubernetes and the client-go (now added in Fabric8 Kubernetes Java Client) called SharedInformer. Let’s see how it works:

We can initialize the informer factory like this:

To get informer for Pod resource, we need to pass classes of Pod , PodList and resync period (which is basically the interval after which informer should set up the connection again).

Because PodSet is a custom resource, we need to pass additional information while creating its informer. It’s not much, just small details related to its custom resource definition (CRD).

Once we have informers for both Pod and PodSet resource, then we need to pass all these into PodSetController (would be discussed after this). After that, we would initialize the controller and run it. Now our PodSetOperatorMain would look like this:

Now we need to take a look at PodSetController , which contains the main logic for interacting with Kubernetes APIs and making the desired changes as per the events received. Let’s first look at its create() method:

As we can see it’s adding event handlers for both informers: Pod and PodSet . In the case of PodSet , we’re adding it to the work queue of the operator to process it afterward. In the case of Pod , we’re checking whether that Pod resource is related to our PodSet custom resource or not, then only we’re trying to handle it (i.e., getting its owner from the metadata and checking the state of owner again).

Let’s look at run() method of our controller; it is just de-queuing item from the work queue and passing it to reconcile() method, which does the main work. Here is the body of reconcile() method:

This reconcile() method seems to be doing the following:

It receives a PodSet object as an argument for which it tries to do reconciliation. Then, it tries to list all the pods in the cluster with the label app=<name of PodSet>; let’s say it’s app=example-podset .

object as an argument for which it tries to do reconciliation. Then, it tries to list all the pods in the cluster with the label let’s say it’s . Once the list operation of all pods with the label app=example-podset is fetched, it checks whether the number of pods is equal to PodSet.spec.replicas. if the number of pods is less, it spins more pods into the cluster.

is fetched, it checks whether the number of pods is equal to PodSet.spec.replicas. if the number of pods is less, it spins more pods into the cluster. If the number of pods is more than the desired value, it tries to delete pods from the cluster.

Running your Operator

We have covered most of the important portions of PodSetController , so let’s try to run our operator on a Kubernetes cluster. I am using Minikube for running this, which you can get from their releases page.

When you run this, you should be able to see pods getting created upon creating a PodSet custom resource as shown in this gif below:

And that’s it! If the above steps worked for you, congratulations! You have successfully written an operator in Java.

See more

GitHub repository: https://github.com/rohanKanojia/podsetoperatorinjava