Eclipse Jkube

We as Java developers are often busy working on our applications by optimizing application memory, speed, etc. In recent years, encapsulating our applications into lightweight, independent units called containers has become quite a trend, and almost every enterprise is trying to shift its infrastructure onto container technologies like Docker and Kubernetes.

Kubernetes is an open source system for automating deployment, scaling, and management of containerized applications, but it has a steep learning curve, and an application developer with no background in DevOps can find this system a bit overwhelming. In this article, I will talk about tools that can help when deploying your Maven applications to Kubernetes/Red Hat OpenShift.

Background: Eclipse JKube

This project was not built from scratch. It’s just a refactored and rebranded version of the Fabric8 Maven plugin, which was a Maven plugin used in the Fabric8 ecosystem. Although the Fabric8 project was liked and appreciated by many people in the open source community, due to unfortunate reasons it could not become successful, and the idea of Fabric8 as an integrated development platform on top of Kubernetes died. Although the main project is archived, there are still active repositories used by the community, such as the Fabric8 Docker Maven plugin, the Fabric8 Kubernetes client, and of course the Fabric8 Maven plugin.

As maintainers of the Fabric8 Maven plugin, we started decoupling the Fabric8 ecosystem related pieces from the plugin to make a general-purpose Kubernetes/OpenShift plugin. We also felt there was a need for rebranding because most people were confused about whether this plugin had something to do with Fabric8. Hence, we decided to rebrand it, and fortunately, someone from the Eclipse foundation approached us to take in our project. Now, the project is being renamed to Eclipse JKube and can be found in the Eclipse Foundation repos on GitHub.

Eclipse JKube can be seen as a reincarnation of the Fabric8 Maven plugin. It contains the good parts of this plugin and offers a clean and smooth workflow with the tooling it provides. We refactored this plugin into three components:

The JKube Kit contains the core logic for building Docker images, generating Kubernetes/OpenShift manifests, and applying them onto Kubernetes/OpenShift clusters. Plugins consume this library for their operations. In the future, we also plan to add support for Gradle plugins.

Example

Now, let’s have a look at Eclipse JKube in action. For the demo, I will deploy a simple Spring Boot project onto Kubernetes using the Eclipse Kubernetes Maven plugin. Let's walk through this process:

  1. Add the Kubernetes Maven plugin as a dependency in your pom.xml file, as shown here:
<plugin>
    <groupId>org.eclipse.jkube</groupId>
    <artifactId>kubernetes-maven-plugin</artifactId>
    <version>${jkube.version}</version>
</plugin>
  1. Build your Docker images. The Eclipse JKube Kubernetes Maven plugin offers a zero-config mode, in which it builds your Docker image with opinionated defaults. Right now I'm just customizing the name of the image created with the jkube.generator.name property to include my Docker Hub username. However, you can also customize it by providing an image configuration in the plugin configuration.Here is an example with my DockerHub username:
    <jkube.generator.name>docker.io/rohankanojia/random-generator:${project.version}</jkube.generator.name>

    All right, you're now set to containerize your application using Eclipse JKube. In order to build a Docker image, you just need to run the following:

eclipse-jkube-demo-project : $ mvn k8s:build
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< meetup:random-generator >-----------------------
[INFO] Building random-generator 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- kubernetes-maven-plugin:1.0.1:build (default-cli) @ random-generator ---
[INFO] k8s: Running in Kubernetes mode
[INFO] k8s: Building Docker image in Kubernetes mode
[INFO] k8s: Running generator spring-boot
[INFO] k8s: spring-boot: Using Docker image quay.io/jkube/jkube-java-binary-s2i:0.0.8 as base / builder
[INFO] k8s: Pulling from jkube/jkube-java-binary-s2i
0fd3b5213a9b: Pulling fs layer 
aebb8c556853: Pulling fs layer 
0fd3b5213a9b: Downloading [>                                                  ]  539.5kB/54.37MB
595bd04e186b: Downloading [>                                                  ]  2.158MB/133.7MB
0fd3b5213a9b: Downloading [>                                                  ]   1.08MB/54.37MB
595bd04e186b: Downloading [=>                                                 ]  5.349MB/133.7MB
0fd3b5213a9b: Downloading [=>                                                 ]  1.621MB/54.37MB
595bd04e186b: Downloading [===>                                               ]  8.572MB/133.7MB
0fd3b5213a9b: Downloading [=>                                                 ]  2.162MB/54.37MB
0fd3b5213a9b: Downloading [==>                                                ]  2.702MB/54.37MB
0fd3b5213a9b: Downloading [==>                                                ]  3.243MB/54.37MB
0fd3b5213a9b: Downloading [===>                                               ]  3.784MB/54.37MB
595bd04e186b: Downloading [=====>                                             ]  14.43MB/133.7MB
0fd3b5213a9b: Downloading [===>                                               ]  4.324MB/54.37MB
0fd3b5213a9b: Downloading [====>                                              ]  5.406MB/54.37MB
0fd3b5213a9b: Downloading [=====>                                             ]  6.487MB/54.37MB
0fd3b5213a9b: Downloading [======>                                            ]  7.568MB/54.37MB
595bd04e186b: Downloading [=======>                                           ]  19.79MB/133.7MB
0fd3b5213a9b: Downloading [=======>                                           ]   8.65MB/54.37MB
0fd3b5213a9b: Downloading [========>                                          ]  9.731MB/54.37MB
0fd3b5213a9b: Downloading [=========>                                         ]  10.27MB/54.37MB
0fd3b5213a9b: Downloading [=========>                                         ]  10.81MB/54.37MB
0fd3b5213a9b: Pull complete 
aebb8c556853: Pull complete 
595bd04e186b: Pull complete 
[INFO] k8s: Digest: sha256:69cacf4092e7ac1765395798d42c16efe2bf88e71472eaffbd2764d0ae95a8fe
[INFO] k8s: Status: Downloaded newer image for quay.io/jkube/jkube-java-binary-s2i:0.0.8
[INFO] k8s: Pulled quay.io/jkube/jkube-java-binary-s2i:0.0.8 in 27 seconds 
[INFO] k8s: [rohankanojia/random-generator:0.0.1] "spring-boot": Created docker-build.tar in 141 milliseconds
[INFO] k8s: [rohankanojia/random-generator:0.0.1] "spring-boot": Built image sha256:a3c06
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  33.047 s
[INFO] Finished at: 2020-10-13T23:52:24+05:30
[INFO] ------------------------------------------------------------------------
eclipse-jkube-demo-project : $ docker images | grep random-generator
rohankanojia/random-generator                 0.0.1               a3c06251eed7        9 seconds ago       528 MB
  1. Generate your Kubernetes resource manifests. Eclipse JKube plugins have a powerful and configurable resource generation mechanism allowing them to generate Kubernetes resources in zero-config mode. This feature can also be configured using XML configuration or by placing customized resource fragments in the src/main/jkube directory. The results are merged with the final generated resource fragments.In order to generate resources, run the following:
eclipse-jkube-demo-project : $ mvn k8s:resource
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< meetup:random-generator >-----------------------
[INFO] Building random-generator 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- kubernetes-maven-plugin:1.0.1:resource (default-cli) @ random-generator ---
[INFO] k8s: Running generator spring-boot
[INFO] k8s: spring-boot: Using Docker image quay.io/jkube/jkube-java-binary-s2i:0.0.8 as base / builder
[INFO] k8s: Using resource templates from /home/rohaan/work/repos/eclipse-jkube-demo-project/src/main/jkube
[INFO] k8s: jkube-controller: Adding a default Deployment
[INFO] k8s: jkube-service: Adding a default service 'random-generator' with ports [8080]
[INFO] k8s: jkube-healthcheck-spring-boot: Adding readiness probe on port 8080, path='/actuator/health', scheme='HTTP', with initial delay 10 seconds
[INFO] k8s: jkube-healthcheck-spring-boot: Adding liveness probe on port 8080, path='/actuator/health', scheme='HTTP', with initial delay 180 seconds
[INFO] k8s: jkube-revision-history: Adding revision history limit to 2
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.940 s
[INFO] Finished at: 2020-10-13T23:53:39+05:30
[INFO] ------------------------------------------------------------------------
eclipse-jkube-demo-project : $ ls target/classes/META-INF/jkube/
kubernetes  kubernetes.yml
eclipse-jkube-demo-project : $ ls target/classes/META-INF/jkube/kubernetes
random-generator-deployment.yml  random-generator-service.yml
eclipse-jkube-demo-project : $ 
  1. Apply generated Kubernetes resources onto the Kubernetes cluster. In order to apply resources onto this cluster, run one of the following commands (results shown in the listing below):
$ mvn k8s:apply

or:

$ mvn k8s:deploy

eclipse-jkube-demo-project : $ mvn k8s:apply
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< meetup:random-generator >-----------------------
[INFO] Building random-generator 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- kubernetes-maven-plugin:1.0.1:apply (default-cli) @ random-generator ---
[INFO] k8s: Using Kubernetes at https://192.168.39.129:8443/ in namespace default with manifest /home/rohaan/work/repos/eclipse-jkube-demo-project/target/classes/META-INF/jkube/kubernetes.yml 
[INFO] k8s: Using namespace: default
[INFO] k8s: Creating a Service from kubernetes.yml namespace default name random-generator
[INFO] k8s: Created Service: target/jkube/applyJson/default/service-random-generator.json
[INFO] k8s: Creating a Deployment from kubernetes.yml namespace default name random-generator
[INFO] k8s: Created Deployment: target/jkube/applyJson/default/deployment-random-generator.json
[INFO] k8s: HINT: Use the command `kubectl get pods -w` to watch your pods start up
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  8.282 s
[INFO] Finished at: 2020-10-13T23:55:10+05:30
[INFO] ------------------------------------------------------------------------
eclipse-jkube-demo-project : $ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
random-generator-8697c5d7d6-k9s7d   0/1     Running   0          9s
eclipse-jkube-demo-project : $ kubectl get all
NAME                                    READY   STATUS    RESTARTS   AGE
pod/random-generator-8697c5d7d6-k9s7d   0/1     Running   0          12s

NAME                       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/kubernetes         ClusterIP   10.96.0.1      <none>        443/TCP          4h3m
service/random-generator   NodePort    10.106.53.34   <none>        8080:32404/TCP   12s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/random-generator   0/1     1            0           12s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/random-generator-8697c5d7d6   1         1         0       12s
eclipse-jkube-demo-project : $ kubectl get svc
NAME               TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
kubernetes         ClusterIP   10.96.0.1      <none>        443/TCP          4h4m
random-generator   NodePort    10.106.53.34   <none>        8080:32404/TCP   36s
eclipse-jkube-demo-project : $ curl `minikube ip`:32404/random | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    45    0    45    0     0   2500      0 --:--:-- --:--:-- --:--:--  2500
{
  "id": "fb4f1cdb-cdd2-4604-ada3-35c27ebd733b"
}
  1. Undeploy your Maven application from Kubernetes. We have a cleanup goal, too, which just deletes all resources created during the deploy phase. To use this feature, run the following (results shown in the listing below):
$ mvn k8s:undeploy
eclipse-jkube-demo-project : $ kubectl get all
NAME                                    READY   STATUS    RESTARTS   AGE
pod/random-generator-8697c5d7d6-mxv7g   1/1     Running   0          45s

NAME                       TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE
service/kubernetes         ClusterIP   10.96.0.1     <none>        443/TCP          4h7m
service/random-generator   NodePort    10.107.3.32   <none>        8080:32287/TCP   45s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/random-generator   1/1     1            1           45s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/random-generator-8697c5d7d6   1         1         1       45s
eclipse-jkube-demo-project : $ mvn k8s:undeploy
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< meetup:random-generator >-----------------------
[INFO] Building random-generator 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- kubernetes-maven-plugin:1.0.1:undeploy (default-cli) @ random-generator ---
[INFO] k8s: Deleting resource Deployment default/random-generator
[INFO] k8s: Deleting resource Service default/random-generator
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  2.662 s
[INFO] Finished at: 2020-10-13T23:58:39+05:30
[INFO] ------------------------------------------------------------------------
eclipse-jkube-demo-project : $ kubectl get all
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   4h7m
eclipse-jkube-demo-project : $ 
  1. Debug your Java application inside Kubernetes. Apart from these goals, we also have a goal for remote debugging. Suppose that you see a bug inside your application that's running inside Kubernetes and you want to debug its behavior. You can simply run our debug goal, which does port forwarding for debugging:
eclipse-jkube-demo-project : $ mvn k8s:debug
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< meetup:random-generator >-----------------------
[INFO] Building random-generator 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- kubernetes-maven-plugin:1.0.1:debug (default-cli) @ random-generator ---
[INFO] k8s: Using Kubernetes at https://192.168.39.129:8443/ in namespace default with manifest /home/rohaan/work/repos/eclipse-jkube-demo-project/target/classes/META-INF/jkube/kubernetes.yml 
[INFO] k8s: Using namespace: default
[INFO] k8s: Updating Service from kubernetes.yml
[INFO] k8s: Updated Service: target/jkube/applyJson/default/service-random-generator-5.json
[INFO] k8s: Enabling debug on Deployment random-generator
[INFO] k8s: Waiting for debug pod with selector LabelSelector(matchExpressions=[], matchLabels={app=random-generator, provider=jkube, group=meetup}, additionalProperties={}) and environment variables {JAVA_DEBUG_SUSPEND=false, JAVA_ENABLE_DEBUG=true}
[INFO] k8s: Port forwarding to port 5005 on pod random-generator-69f9947655-ws4pk using command /home/rohaan/.local/bin/kubectl
  1. Configure your IDE in order to connect to this open port for debugging, as shown in Figure 1:
Figure 1: Configuring your IDE to debug application inside Kubernetes.
  1. Set a breakpoint in the application code and hit the application endpoint. We can see the breakpoint being hit in IDE as shown in Figure 2:
Figure 2: Configuring your IDE to debug an application running inside Kubernetes.
Figure 2: Configuring your IDE to debug an application running inside Kubernetes.
Figure 2: Configuring your IDE to debug an application running inside Kubernetes.

Deploying to Red Hat OpenShift:

You can deploy the same application to Red Hat OpenShift using Eclipse JKube's OpenShift Maven Plugin. Here is how you would do it:

  1. Add OpenShift Maven Plugin in <plugins> section of your pom.xml:
<plugin>
    <groupId>org.eclipse.jkube</groupId>
    <artifactId>openshift-maven-plugin</artifactId>
    <version>${jkube.version}</version>
</plugin>
  1. Log into your OpenShift Cluster:
$ oc login https://api.example.openshift.com --token=some-token
Logged into "https://api.example.openshift.com:443" as "rohanKanojia" using the token provided.

You have one project on this server: "rokumar"

Using project "rokumar".
    1. Build your application and run the usual goals as Kubernetes Maven Plugin but with the oc prefix. The image is built inside Build Pod and pushed to OpenShift internal registry. Since we won't need to push the image to some other registry, we can delete the jkube.generator.name property that we configured for pushing our image to docker hub:
-        <jkube.generator.name>docker.io/rohankanojia/random-generator:${project.version}</jkube.generator.name>

Once the property is deleted, you can proceed with the usual flow for deploying to Red Hat OpenShift:

eclipse-jkube-demo-project : $ mvn oc:build oc:resource oc:apply
[INFO] Scanning for projects...
[INFO] 
[INFO] ----------------------< meetup:random-generator >-----------------------
[INFO] Building random-generator 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- openshift-maven-plugin:1.0.1:build (default-cli) @ random-generator ---
[INFO] oc: Using OpenShift build with strategy S2I
[INFO] oc: Running in OpenShift mode
[INFO] oc: Running generator spring-boot
[INFO] oc: spring-boot: Using Docker image quay.io/jkube/jkube-java-binary-s2i:0.0.8 as base / builder
[INFO] oc: [random-generator:0.0.1] "spring-boot": Created docker source tar /home/rohaan/work/repos/eclipse-jkube-demo-project/target/docker/random-generator/0.0.1/tmp/docker-build.tar
[INFO] oc: Adding to Secret pullsecret-jkube
[INFO] oc: Using Secret pullsecret-jkube
[INFO] oc: Creating BuildServiceConfig random-generator-s2i for Source build
[INFO] oc: Creating ImageStream random-generator
[INFO] oc: Starting Build random-generator-s2i
[INFO] oc: Waiting for build random-generator-s2i-1 to complete...
[INFO] oc: Using quay.io/jkube/jkube-java-binary-s2i:0.0.8 as the s2i builder image
[INFO] oc: INFO S2I source build with plain binaries detected
[INFO] oc: INFO S2I binary build from fabric8-maven-plugin detected
[INFO] oc: INFO Copying binaries from /tmp/src/deployments to /deployments ...
[INFO] oc: random-generator-0.0.1.jar
[INFO] oc: INFO Copying deployments from deployments to /deployments...
[INFO] oc: '/tmp/src/deployments/random-generator-0.0.1.jar' -> '/deployments/random-generator-0.0.1.jar'
[INFO] oc: INFO Cleaning up source directory (/tmp/src)
[INFO] oc: 
[INFO] oc: Pushing image 172.30.39.149:5000/rokumar/random-generator:0.0.1 ...
[INFO] oc: Pushed 3/4 layers, 95% complete
[INFO] oc: Pushed 4/4 layers, 100% complete
[INFO] oc: Push successful
[INFO] oc: Build random-generator-s2i-1 in status Complete
[INFO] oc: Found tag on ImageStream random-generator tag: sha256:4c71b89b5345db80ab4802e127085ac45bd1410e6e91439fad956fe12200b93c
[INFO] oc: ImageStream random-generator written to /home/rohaan/work/repos/eclipse-jkube-demo-project/target/random-generator-is.yml
[INFO] 
[INFO] --- openshift-maven-plugin:1.0.1:resource (default-cli) @ random-generator ---
[INFO] oc: Using docker image name of namespace: rokumar
[INFO] oc: Running generator spring-boot
[INFO] oc: spring-boot: Using Docker image quay.io/jkube/jkube-java-binary-s2i:0.0.8 as base / builder
[INFO] oc: Using resource templates from /home/rohaan/work/repos/eclipse-jkube-demo-project/src/main/jkube
[INFO] oc: jkube-controller: Adding a default DeploymentConfig
[INFO] oc: jkube-service: Adding a default service 'random-generator' with ports [8080]
[INFO] oc: jkube-healthcheck-spring-boot: Adding readiness probe on port 8080, path='/actuator/health', scheme='HTTP', with initial delay 10 seconds
[INFO] oc: jkube-healthcheck-spring-boot: Adding liveness probe on port 8080, path='/actuator/health', scheme='HTTP', with initial delay 180 seconds
[INFO] oc: jkube-revision-history: Adding revision history limit to 2
[INFO] 
[INFO] --- openshift-maven-plugin:1.0.1:apply (default-cli) @ random-generator ---
[INFO] oc: Using OpenShift at https://api.rh-idev.openshift.com:443/ in namespace rokumar with manifest /home/rohaan/work/repos/eclipse-jkube-demo-project/target/classes/META-INF/jkube/openshift.yml 
[INFO] oc: OpenShift platform detected
[INFO] oc: Using project: rokumar
[INFO] oc: Creating a Service from openshift.yml namespace rokumar name random-generator
[INFO] oc: Created Service: target/jkube/applyJson/rokumar/service-random-generator.json
[INFO] oc: Creating a DeploymentConfig from openshift.yml namespace rokumar name random-generator
[INFO] oc: Created DeploymentConfig: target/jkube/applyJson/rokumar/deploymentconfig-random-generator.json
[INFO] oc: Creating Route rokumar:random-generator host: null
[INFO] oc: HINT: Use the command `oc get pods -w` to watch your pods start up
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  48.578 s
[INFO] Finished at: 2020-10-14T00:57:20+05:30
[INFO] ------------------------------------------------------------------------
eclipse-jkube-demo-project : $ oc get pods
NAME                           READY     STATUS      RESTARTS   AGE
random-generator-1-vtdzs       1/1       Running     0          4m
random-generator-s2i-1-build   0/1       Completed   0          5m
eclipse-jkube-demo-project : $ oc get routes
NAME               HOST/PORT                                                 PATH      SERVICES           PORT      TERMINATION   WILDCARD
random-generator   random-generator-rokumar.b6ff.rh-idev.openshiftapps.com             random-generator   8080                    None
eclipse-jkube-demo-project : $ curl random-generator-rokumar.b6ff.rh-idev.openshiftapps.com/random | jq .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    45    0    45    0     0     62      0 --:--:-- --:--:-- --:--:--    62
{
  "id": "c656151e-c48a-4331-b265-859a16209b14"
}

With this result, I wrap up this article. We do have more in our pipeline, so stay tuned for new updates.

Conclusion:

Whether you are already using Eclipse JKube or just curious about it, don’t be shy about joining our welcoming community:

Last updated: October 28, 2020