Build and Deploy a Spring Boot App on Kubernetes (Minikube)

In my last post, you learned about the main components of Kubernetes and how you could take advantage of them.

In this post, I will explain how to deploy a Java 8 Spring Boot application on a Kubernetes cluster. This will offer you the chance to familiarize yourself with the fundamental concepts of building an application and deploying it on Kubernetes.

Clarification: It doesn’t matter if you have no experience with Spring Boot; you can still follow along using another framework or programming language. With that clarified, let’s get started.

Step 1: Create a ‘Hello Gorillas’ Spring Boot application

My starting point when I want to create a Spring Boot app is https://start.spring.io/. To get started, select Java 8 and Spring Boot 2.0.3, and choose “Web and Spring Actuator.” Click on the “Generate project” button; this will download the new project with its dependencies.

1 Generate Project

Open the project with your favorite IDE (I use IntelliJ). I will develop a basic Spring Boot application with one endpoint that returns a “Hello Gorillas! We love Kubernetes” message. So, I added the following class called “HelloController” to the project:

2 HelloController

Run the application, open a browser and type in http://localhost:8080/hello; if everything worked well, you should see the message “Hello Gorillas! We love Kubernetes” displayed in your browser.

3 Hello Gorillas!

Step 2: Create a Docker image

The next step after you have the application running is to create a Docker file that has an image of Java 8 and will place the JAR file generated by our application in it. The Docker file should look like this:

4 Docker file

As you have probably already guessed, I placed the file inside the root of the application.

We can build a Docker image and push it to a Docker registry by using a Maven plugin. In order to do that, I recommend using the dockerfile-maven-plugin developed by Spotify, since it is very straightforward to use and implement. I will be using this plugin, but if you prefer to create the Docker image in a different way, no worries.

Open the pom.xml file created by the application and add a property called dockerfile-maven-version:

5 dockerfile-maven-version

Then, add the plugin to create a Docker image by using Maven (as mentioned above):

6 plugin

Note: You will need to use your own information for the “username,” “password” and “repository” properties.

Ok, the time to build our image has come. Most IDEs such as IntelliJ, STS, and Eclipse have incorporated plugins or tools that allow us to execute Maven tasks. Since my favorite code editor is IntelliJ, I will take advantage of the tools that this IDE offers. In IntelliJ, there is a Maven Projects tab on the right sidebar. Click on it.

7 Maven Projects Sidebar

You should see the following options:

8 Maven projects

Double click on the “install” option; it will build our project and Docker image. Before you do this, though, make sure that your local Docker is running. If everything was successful, the code editor console should show the following:

9 success

You also can verify that the Docker image was created by using the “docker images” command in the terminal:

docker images
10 docker images

Now that the Docker image has been created, we can push it to the Docker hub. Go to IntelliJ → Maven projects tab → Plugins → Dockerfile → Push.

11 docker hub

The code editor’s console should show the log message “BUILD SUCCESS,” indicating that the Docker image was pushed successfully.

Step 3: Install Kubernetes locally (Minikube)

According to official documentation (https://kubernetes.io/docs/setup/minikube/):

“Minikube is a tool that makes it easy to run Kubernetes locally. Minikube runs a single-node Kubernetes cluster inside a VM on your laptop for users looking to try out Kubernetes or develop with it day-to-day.”

Go to the Minikube project page on GitHub for information on how to download and install it on Windows, Linux or macOS. We’ll also need Kubectl, which is a command line tool that allows us to manage and deploy applications on Kubernetes. It is also important to mention that Minikube works with Virtual Box by default, but if you want to use another VM driver, you can do so. For more info, click here.

After installing Minikube and Kubectl, we should start the Minikube cluster with the following command:

minikube start

Minikube created a virtual machine, and inside it, a cluster is now running. If everything went well, the console should show the following log messages:

12 log messages

If we want to validate the state of Kubernetes resources in our cluster, we can use Kubernetes Dashboard; the command is “minikube dashboard.” A web browser will be opened with the following dashboard:

13 Kubernetes Dashboard

Step 4: Deploy the app on Kubernetes

First, we should check the information of our cluster:

sudo kubectl cluster-info

Remember: The master (API server) manages the cluster. In addition, each node has a Kubelet, which is responsible for communicating with the master.

Now, we are able to see that our master cluster is up and running:

14 master cluster

It is important to clarify that Minikube only has one cluster with its respective node. So, we could check our nodes using the command “sudo kubectl get nodes.” The output looks like this:

15 cluster

For this post, we only need a master node, but obviously in production mode we would probably have to use at least three nodes: one for the master, and two nodes for all the things related to application redundancy.

The following step is to deploy our application on Kubernetes. In order to do that, we need to implement a Deployment configuration. With Kubernetes Deployments, you can “describe a desired state in a Deployment object, and the Deployment controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new ReplicaSets, or to remove existing Deployments and adopt all their resources with new Deployments,” according to the official doc.

In order to create a Kubernetes Deployment, you should run the following command:

sudo kubectl run {DEPLOYMENT_NAME} --image= {YOUR_IMAGE} --port=8080

The command “kubectl run” only needs the {DEPLOYMENT_NAME} to work, but if you want to pull a Docker image inside this deployment, you should use the “ — image” option, with which you can specify the Docker image to be used.

For this post, I will use the Docker image that was created previously, so the command would be:

sudo kubectl run mykubernetes-springboot 
--image=glgelopfalcon/springboot_docker_maven:0.0.1-SNAPSHOT --port=8080

You can check the deployment that we created by using the command:

sudo kubectl get deployments

The console output should look like this:

NAME                      DESIRED   CURRENT   UP-TO-DATE   
mykubernetes-springboot 1 1 1

Congratulations, you now have a Deployment containing a Pod that is running the Spring Boot application! Kubernetes created a Deployment and a Pod for us; now we need to know the name of our Pod. To do so, you can use the following command:

sudo kubectl get pods

The console output will be:

NAME                                                                          READY     STATUS    
mykubernetes-springboot-6f8558698d-k4ns7 1/1 Running

Now that we know the name of our Pod, we can execute commands on it. For example, we could open a bash terminal or show the environment variables:

sudo kubectl exec -ti mykubernetes-springboot-6f8558698d-k4ns7 bash
sudo kubectl exec mykubernetes-springboot-6f8558698d-k4ns7 env

Currently, our application isn’t accessible from outside the cluster; it is only running on the Kubernetes cluster. We need to create a “bridge” between our application and the outside world, something that can be done by using a service. Let’s go ahead and create our service, because we want everyone to be able to use our application:

sudo kubectl expose deployment/mykubernetes-springboot --type="NodePort" --port 8080

The logic behind the above command is the following: we want to expose our deployment to the world through the NodePort (which will be assigned when the service is created). After you execute the command, a console message will appear: “service ‘mykubernetes-springboot’ exposed,” which means that the application can be accessed from outside the cluster. We now need to know the NodePort of the service that was created. To do this, in addition to obtaining more details about our service, we can use the following command:

kubectl describe services/mykubernetes-springboot

The above command will show us the details about our service:

Name: mykubernetes-springboot
 Namespace: default
 Labels: run=mykubernetes-springboot
 Annotations: <none>
 Selector: run=mykubernetes-springboot
 Type: NodePort
 IP: 10.109.185.97
 Port: <unset> 8080/TCP
 TargetPort: 8080/TCP
 NodePort: <unset> 30961/TCP
 Endpoints: 172.17.0.3:8080
 Session Affinity: None
 External Traffic Policy: Cluster
 Events: <none>

It is time to access our application. Remember that the application lives inside a Pod, and we’ve created a service that allows us to access the application from outside the cluster. Use the following command to see which Minikube IP you have:

minikube ip

In my case, the IP is http://192.168.99.100/ and the NodePort is 30961. Go to your favorite browser and type: http://192.168.99.100:30961/hello. You can see that the application is running and can be accessed from outside the Kubernetes cluster:

16 output

You rock! You have turned a simple Java Spring Boot app into an application running on Kubernetes.

Conclusion

We implemented and deployed our application on the Kubernetes cluster; in addition, we used Kubectl to execute commands on the cluster. You should now have a basic understanding of how Kubernetes works, so feel free to create more deployments and communicate with them by using services.

Subscribe to our Blog