Deploying a Spring Boot App to Kubernetes (Minikube)

Deploying a Spring Boot application to Kubernetes can seem daunting at first, but with the right tools and knowledge, it can be a straightforward process. In this post, we will walk through the steps needed to deploy a dockerized Spring Boot application to Kubernetes (Minikube).

1. Prerequisites

Before we begin, make sure we have the following:

  • A Kubernetes cluster up and running.
  • Docker installed.
  • kubectl installed.

2. Introduction to Kubernetes

Kubernetes is an open-source, portable, and extensible platform for managing workloads and services deployed in containers. Kubernetes facilitates both declarative configuration and automation. The Kubernetes platform has a rich and rapidly growing ecosystem, and its support, services, and tools are widely available.

Kubernetes is based on a decade and a half of experience that Google has in running production workloads at scale, along with the best ideas and practices suggested by the community.

Key components of kubernetes are:

  • Nodes: Nodes are responsible for running containers, communicating with the master, and reporting the status of their assigned tasks.
  • Pods: Pods are the smallest objects in a kubernetes cluster located on a node.
  • ReplicaSets: Allows us to scale the number of replicas up or down based on the demand.
  • Services: A Service is an object used to direct requests or traffic to multiple Pods using an IP address.
  • Cluster :Basicly, a Kubernetes cluster is a sort of host for your running containers. and each Node clusters will have at least one master node and warker nodes; this master node is responsible for keeping the overall cluster in a desirable state based on the configuration and the workerNode is the one that runs applications inside a container.

3. Initialize a Spring Boot Application

To quickly generate a simple project, use Spring Initializer.

Then, create an endpoint called controller to verify everything is working properly when deploying the project.

@RestController
public class FooController {

   @RequestMapping(value="/controller", method=RequestMethod.GET)
   public String foo() {
      return "Response!";
   }

}

In this example, we create an endpoint called controller, so if we send a request to the endpoint, we should get the message response!

Test our Application

Next, create an executable JAR file to the folder /target, use maven install. If you don’t know how, check out Creating Spring Boot Fat/Uber Jar or War Files.

$ mvn clean install

4. Dockerize Spring Boot Application

To containerize the application, create a Dockerfile with the following instructions:

FROM openjdk:17
VOLUME /tmp
EXPOSE 8080
ARG JAR_FILE=target/spring-demo-0.0.1-SNAPSHOT.jar 
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

Next, build the image with the command docker build.

docker build

Go Deep on Docker: Check How To Dockerize a Spring Boot Application

5. Deploy to Minikube

5.1. Installation

Minikube provides an easy way to set up a local Kubernetes environment for testing and development purposes. We can find the installation instructions for our system at Minikube Installation.

Install Minikube and check its status with the command minikube status.

Check minikube status

If it’s not running, use the command minikube start to start it.

start minikube

After starting Minikube, we need to tell Minikube to read our local image. Use the command.

$ eval $(minikube docker-env)

5.2. Deployment

Now, we have two options to start deploying our application: using kubectl commands or a YAML file with the whole configuration. We will use a YAML file.

In the root folder of your application, create a file with any name, but the extension should be .yaml. with the following instructions:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: spring-app
  template:
    metadata:
      labels:
        app: spring-app
    spec:
      containers:
        - name: spring-app
          image: springboot-app:latest
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080

This is a YAML file that describes a Kubernetes deployment for a containerized application. Let’s go through the different parts of the file:

  • apiVersion: The Kubernetes API version used by the deployment.
  • kind: The type of Kubernetes resource being created.
  • metadata: This contains metadata about the deployment, such as the name of the deployment.
  • spec: The desired state of the deployment.
    • replicas: The number of replicas (instances) of the application to run.
    • selector: The labels used to identify the pods that belong to the deployment. In this case, it is looking for pods with the label app: spring-app.
    • template: The pod template used to create new pods for the deployment.
    • metadata: The labels used to identify the pod.
      • spec: The pod specification, including the container(s) to run.
        • containers: The container(s) to run within the pod.
          • name: The container name.
          • image: Name of the docker image that we gonna use for the container.
          • ports: The ports to expose for the container.

Make sure you add imagePullPolicy: IfNotPresent. This tells Minikube to search for the image locally first and then, if it’s not present, to search on the Docker Hub.

Here we will create a yaml file called deployment.yaml with the above content, and then all we need to do is tell kubectl to take the file and create the deployment object for us with the following command:

$ kubectl apply -f deployment.yaml
create a deployment object

5.3. Verification

When we execute this, that means we create the deployment object, and we can verify that with:

$ kubectl get deployments
check deployment

And we can check pods since we define two pods on the yaml file with the command:

$ kubectl get pods
get pods

To check if the pod is working successfully, execute the command:

$ kubectl logs {name of the pod}
check if the pod is working

As the image tells us, everything is running fine.

6. Kubernetes Services

Our application runs on two different pods, which means two different IP addresses. If a user wants to execute our application, which of the two pods will execute?

The answer to this question is Kubernetes services. Services allow us to load balance the traffic between our pods by giving us a single IP address for a group of pods. In our case, we have just two pods. By adding a service, we have a solution to the question of which pod will execute when a user sends a request to our application.

In Kubernetes, there are four types of services:

  • ClusterIP: Provides a stable IP address that is only accessible within the cluster.
  • NodePort: Used to exposes a port on every node in the cluster.
  • LoadBalancer: Creates a load balancer in the cloud provider to distribute traffic to the pods..
  • ExternalName: This type of service maps a DNS name to an external service.
  • Headless: To allows direct access to each pod by DNS name.

Here, we will use NodePort. Create another YAML file with the following:

apiVersion: v1
kind: Service
metadata:
  name: spring-service
spec:
  type: NodePort
  selector:
    app: spring-app
  ports:
  - name: http
    port: 80
    targetPort: 8080
    nodePort: 30005

The only difference from the deployment file is that instead of kind: deployment, it should be service. For the name, you can use any name, but in this case, we will use spring-service.

Make sure that the name of the selector app is the same as what we defined in the deployment file.

spec.ports.nodePort: specifies the port on which the service will be exposed externally. In our case, we’re using port 30005 (The range of valid ports is 30000-32767).

Apply the service with the command:

$ kubectl apply -f service.yaml
apply service

To check if our service is working, execute the command:

$ kubectl get svc
get service

7. Demo

Now that our service is working, we need to get the node IP with kubectl get nodes -o wide so that we can access our app.

Get node ip

Now, with the IP and port, we can access our app. In our case, the IP is 192.168.49.2 and the port is 30005. The final URL is 192.168.49.2:30005/controller, where controller is the endpoint that we created earlier.

Check our project on Kubernetes

Congratulations, we have received our response from Kubernetes.

8. Minikube DashBoard

After successfully hosting our app in the Kubernetes cluster, we can access the Minikube dashboard to check the different components.

$ minikube dashboard 
Minikube dashboard

The dashboard shows us all the components that we have; in our example, we have 1 deployment and 2 pods, and we can add or delete whatever we want. Basically, the dashboard is just an interface that allows us to interact with and manage our Kubernetes cluster.

9. Conclusion

In this guide, we learned how to deploy a Spring Boot app step by step to a Kubernetes cluster using a YAML file based deployment. We also learned to configure the k8s services and tested the application by hitting the API request successfully.

Happy Learning !!

Sourcecode on Github

Comments

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode