Authors – All

If you have a few years of experience in the DevOps ecosystem, and you're interested in sharing that experience with the community, have a look at our Contribution Guidelines.

1. Introduction

Now more than ever, Java developers have many options for building and deploying applications with Kubernetes. In this tutorial, we’ll look at one such tool named JKube.

2. What Is JKube?

JKube is a collection of tools that make it easy to build Java applications with the intention of deploying them to a cloud environment. It’s a project managed by the Eclipse Foundation and available to use under their ECL-2.0 license.

More specifically, JKube allows us to compile Java applications into Docker container images and then deploy those images to Kubernetes or OpenShift.

It also provides other tools to make monitoring and debugging cloud applications easier.

3. Getting Started With JKube

Most of the core JKube tools are provided via Maven or Gradle plugins. For brevity, the examples below will focus only on the Maven plugin with a Kubernetes environment.

To get started, we simply add the plugin to our Maven POM:

<plugin>
    <groupId>org.eclipse.jkube</groupId>
    <artifactId>kubernetes-maven-plugin</artifactId>
    <version>1.13.1</version>
</plugin>

Notably, the Maven Kubernetes plugin takes some opinionated views to make setup simple. However, it also supports fine-grain control via XML and YAML configuration. We can see the developer docs for full details.

3.1. Building a Docker Image

Without any further configuration, we can generate a Docker image:

mvn package k8s:build

This inspects the project structure and picks a suitable base image to use:

[INFO] --- kubernetes-maven-plugin:1.13.1:build (default-cli) @ jkube-demo ---
[INFO] k8s: Building Docker image
[INFO] k8s: Running generator spring-boot
[INFO] k8s: spring-boot: Using Docker image quay.io/jkube/jkube-java:0.0.19 as base / builder
[INFO] k8s: [example/jkube-demo:latest] "spring-boot": Created docker-build.tar in 112 milliseconds
[INFO] k8s: [example/jkube-demo:latest] "spring-boot": Built image sha256:6c9d0
[INFO] k8s: [example/jkube-demo:latest] "spring-boot": Removed old image sha256:e2458
[INFO] k8s: [example/jkube-demo:latest] "spring-boot": Tag with latest

And we can confirm the image exists in our local Docker daemon:

> docker image ls
REPOSITORY                                 TAG              IMAGE ID       CREATED         SIZE
example/jkube-demo                         latest           6c9d08bcd538   5 minutes ago   605MB

3.2. Deploying to Kubernetes

In addition to building Docker images, we can use JKube to generate resource descriptors and deploy our application to Kubernetes.

To do this, we need to execute 2 Maven goals:

mvn k8s:resource k8s:apply

The first goal generates a deployment and service YAML file for our application, setting as many defaults as it can:

[INFO] --- kubernetes-maven-plugin:1.13.1:resource (default-cli) @ jkube-demo ---
[INFO] k8s: Running generator spring-boot
[INFO] k8s: spring-boot: Using Docker image quay.io/jkube/jkube-java:0.0.19 as base / builder
[INFO] k8s: Using resource templates from jkube-demo/src/main/jkube
[INFO] k8s: jkube-controller: Adding a default Deployment
[INFO] k8s: jkube-service: Adding a default service 'jkube-demo' with ports [8080]
[INFO] k8s: jkube-service-discovery: Using first mentioned service port '8080'
[INFO] k8s: jkube-revision-history: Adding revision history limit to 2
[INFO] k8s: validating jkube-demo/target/classes/META-INF/jkube/kubernetes/jkube-demo-deployment.yml resource
[INFO] k8s: validating jkube-demo/target/classes/META-INF/jkube/kubernetes/jkube-demo-service.yml resource

The second goal actually deploys to a Kubernetes cluster:

[INFO] --- kubernetes-maven-plugin:1.13.1:apply (default-cli) @ jkube-demo ---
[INFO] k8s: Using Kubernetes at https://kubernetes.docker.internal:6443/ in namespace null with manifest /Users/mike/github/jkube-demo/target/classes/META-INF/jkube/kubernetes.yml
[INFO] k8s: Creating a Service from kubernetes.yml namespace default name jkube-demo
[INFO] k8s: Created Service: target/jkube/applyJson/default/service-jkube-demo.json
[INFO] k8s: Creating a Deployment from kubernetes.yml namespace default name jkube-demo
[INFO] k8s: Created Deployment: target/jkube/applyJson/default/deployment-jkube-demo.json

Finally, we can use JKube to undeploy our application from the Kubernetes cluster:

mvn k8s:undeploy

Remember that each of these commands to build Docker images and deploy to Kubernetes uses opinionated views. However, JKube offers the ability to configure each of them. For full details, see the goals overview.

4. JKube Features

In addition to building Docker images and deploying them to Kubernetes, JKube offers several other tools to help with the development of applications. Below we’ll take a closer look at some of them.

4.1. Log

This goal works similarly to the Unix tail command. It continuously shows the output of a previously deployed application.

To run this goal, we use the following command:

mvn k8s:log

4.2. Debug

The debug goal allows us to attach a Java debugger to a deployed application. Here’s the syntax of the command:

mvn k8s:debug -Djkube.debug.port=8000

Running this command does several things. First, it redeploys the application with debug enabled. Second, it creates a Kubernetes port forward on the specified debug port. After running this command, we can attach a Java debugger to the specified port and begin remote debugging.

Because constantly redeploying our application can be time-consuming, we can speed things up by always deploying with debug enabled. To do this, we have two options. First, we can add an extra flag to the deploy command:

mvn k8s:deploy -Djkube.debug.enabled=true

Alternatively, we can update our Maven settings.xml file:

<?xml version="1.0"?>
<settings>
    <profiles>
        <profile>
            <id>enable-debug</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <jkube.debug.enabled>true</jkube.debug.enabled>
            </properties>
        </profile>
    </profiles>
</settings>

By doing this, we avoid the waiting time while a pod restarts each time we run the debug goal.

4.3. Watch

This goal automatically redeploys an application when it detects changes in the project. To enable it, we run the command:

mvn k8s:watch

With the watch enabled, whenever a file in the project changes, JKube rebuilds and redeploys for us. JKube provides several different watchers for various frameworks, including Spring Boot.

4.4. Push

The build command we saw earlier publishes new images to the local Docker daemon. We can then use the push goal to publish those images to any remote registry:

mvn k8s:push

4.5. Helm

Similar to the resource goal above, this goal generates deployment descriptors for Helm using suitable defaults detected from the project:

mvn k8s:resource k8s:helm

It’s worth noting that we must run the resource goal with the helm goal. This goal has a number of ways to configure the generated Helm chart.

5. Conclusion

In this article, we looked at JKube, a tool that simplifies many aspects of building Java applications for Kubernetes and OpenShift.

Through a robust Maven and Gradle plugin, it provides several tools for building, monitoring, and deploying applications to two of the most popular container management systems available.

The examples above can be found over on GitHub.

Authors – All

If you have a few years of experience in the DevOps ecosystem, and you're interested in sharing that experience with the community, have a look at our Contribution Guidelines.

Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.