Spring Boot With Kubernetes – DZone Microservices

Hello guys! In this tutorial, we will see how a Spring Boot application can be deployed using Kubernetes (K8S) locally.

Kubernetes is an open source container orchestration platform that provides a way to scale your application. The Kubernetes API allows you to automate resource management and provisioning tasks. In addition, Kubernetes is cloud-neutral, can run on AWS, GCP, and Azure, and can also be run on-premises.

Here, we will create a Spring Boot application, build its image using Docker, and publish it on the Kubernetes platform locally.

Initial requirements

  1. Spring Boot application containing Dockerfile and publish.yaml: We will see what Dockerfile and publish.yaml are and what they contain.
  2. Docker Desktop for Windows (I’m using Windows): Docker desktop can be set up via https://docs.docker.com/desktop/windows/install/ (please read minimum requirements to install Docker Desktop).

Spring Boot Application Development

Let’s start by creating a simple Spring Boot application. We will create the student app via https://start.spring.io/.

  1. Go to https://start.spring.io/ and create a Spring Boot application with dependencies: Spring Web, JPA, Lombok, H2 DB. Enter the Tool ID and Group ID as required. Here, I’m naming the app as Experimental ruler student.
  2. Extract the generated project and import it into your favorite IDE. I will be using IntelliJ IDEA.
  3. Create a package for a personality And add the category below to it.
package com.techspeaks.studentkubernetesdemo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer studentId;
    private String name;
    private String email;
}

4. Create a package for Store And add the category below to it.

package com.techspeaks.studentkubernetesdemo.repository;

import com.techspeaks.studentkubernetesdemo.entity.Student;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepository extends JpaRepository<Student,Integer> {
}

5. Create a package for Foreman And add the category below to it.

package com.techspeaks.studentkubernetesdemo.controller;

import com.techspeaks.studentkubernetesdemo.entity.Student;
import com.techspeaks.studentkubernetesdemo.repository.StudentRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;

@RestController
@RequestMapping("/student-records")
public class StudentController {

    @Autowired
    private StudentRepository studentRepository;

    private Logger logger = Logger.getLogger(StudentController.class.getName());

    @PostMapping(value = "/student",produces = "application/json")
    public Student saveStudent(@RequestBody Student student){
        logger.info("Saving a new student");
        Student student1 = studentRepository.save(student);
        return student1;
    }

    @GetMapping(value = "/students",produces = "application/json")
    public List<Student> getStudents(){
        logger.info("Retrieving all students");
        return studentRepository.findAll();
    }

    @GetMapping(value = "/students/{id}",produces = "application/json")
    public Optional<Student> getStudent(@PathVariable("id") Integer id){
        logger.info("Retrieving student by id");
        return studentRepository.findById(id);
    }

    @DeleteMapping("/student/delete/{id}")
    public void deleteStudent(@PathVariable("id") Integer id){
        logger.info("Deleting student by id");
        studentRepository.deleteById(id);
    }
}

6. Spring boot master application

package com.techspeaks.studentkubernetesdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories
public class StudentKubernetesDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(StudentKubernetesDemoApplication.class, args);
	}

}

7. pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.2</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.techspeaks</groupId>
	<artifactId>student-kubernetes-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>student-kubernetes-demo</name>
	<description>Demo project for Spring Boot Kubernetes deployment</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

I think the code here is self-explanatory.

Before moving on to the next part, please build your app with clean install mvn then turn on mvn spring boot: run. This will ensure that our app works.

You can see the generated jar file in . format student-kubernetes-demo-0.0.1-SNAPSHOT.jar inside the target folder.

Noticeable: I’m using Git Bash here for build and run commands.

8. Add a Dockerfile in the root of the project.

FROM openjdk:8
ADD ./target/student-kubernetes-demo-0.0.1-SNAPSHOT.jar student-kubernetes-demo-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar","/student-kubernetes-demo-0.0.1-SNAPSHOT.jar"]

Dockerfile is required by Docker to read and build an image of the application. This image will be further published on the Kubernetes platform.

This Dockerfile has some configuration as below.

a.) From openjdk: 8: This tells us that while creating an image, the openjdk 8 image will be pulled from Docker Hub and used to build our app.

B.) Add ./target/student-kubernetes-demo-0.0.1-SNAPSHOT.jar student-kubernetes-demo-0.0.1-SNAPSHOT.jar: This will add the generated jar file from the target folder to the docker image.

c) entry point [“java”,”-jar”,”/student-kubernetes-demo-0.0.1-SNAPSHOT.jar”]: This is used to set the executables that will always run when the container is executed.

With this Dockerfile, we will see how to create a Docker image for the student application.

Noticeable: The above configuration is also useful when you just want to create an image and publish it to a Docker container.

9. Add a publishing file in the root of the project.

apiVersion: v1 # Kubernetes API version
kind: Service # Kubernetes resource kind we are creating
metadata: # Metadata of the resource kind we are creating
  name: student-kubernetes-demo
spec:
  selector:
    app: student-kubernetes-demo
  ports:
    - protocol: "TCP"
      port: 8080 # The port that the service is running on in the cluster
      targetPort: 8080 # The port exposed by the service
  type: LoadBalancer # type of the service. LoadBalancer indicates that our service will be external.
---
apiVersion: apps/v1
kind: Deployment # Kubernetes resource kind we are creating
metadata:
  name: student-kubernetes-demo
spec:
  selector:
    matchLabels:
      app: student-kubernetes-demo
  replicas: 2 # Number of replicas that will be created for this deployment
  template:
    metadata:
      labels:
        app: student-kubernetes-demo
    spec:
      containers:
        - name: student-kubernetes-demo
          image: student-kubernetes-demo # Image that will be used inside the container in the cluster
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080 # The port that the container is running on in the cluster

The publish.yaml file basically contains two parts.

a.) Type: Service: This part contains some metadata related to the application (such as the name of the service), then information about the ports and type of services, in this case LoadBalancer.

B.) Genre: Publishing: This part also contains similar metadata (such as the post name), then the replicas you need, container information, or configuration as specified.

With this .yaml deployment, we will see how to publish the Docker image created above to a Kubernetes cluster.

Construction and publishing department

  1. I will be using Git Bash here to build and execute commands.
  2. Start the Docker drive first from the Docker desktop. This step is mandatory.
  3. Go to your project folder and right click and choose Git Bash here.
  4. Docker image build command: build docker -t dialer-kubernetes-demo. (Make sure you have a “.” at the end, which tells us that your Dockerfile is in the project root, and also make sure that this image name is the same in the publish.yaml file.)

Command to build a docker image

5. At first, it may take some time to build. After the command is executed successfully, check if the image is built using the command: docker pictures.

Docker images . command

6. If all is well, we will continue to post this image on the Kubernetes group.

7. First, go to Docker desktop settings and make sure under Kubernetes that the Enable Kubernetes check box is checked. Please mark if not.

Activate Kubernetes

8. Now back to Git Bash, we will first check the Kubernetes cluster using the commands below. We will use the kubectl command (this step is optional).

  • kubectl get contract: This name should appear as a docker desktop along with the control plane and master roles. The Kubernetes family consists of a group of working machines called nodes that run containerized applications. Each block has at least one working node.

The working node(s) host the pods which are components of the application’s workload. The control plane manages the running nodes and pods in the cluster.

Control plane components make global decisions about the block (for example, scheduling), as well as detect and respond to block events.

The master node is a node that controls and manages a group of working nodes (workload runtime) and is similar to a group in Kubernetes.

More information is available at https://kubernetes.io/docs/concepts/overview/components/.

Kubectl get the contract

  • kubectl get pods: This will be blank before the image is posted.

Kubectl Get the pods

9. Now we will publish the photo kubectl application -f publish. yaml. This command reads the instructions from the deployment process. yaml and creates the post. If all goes well, you will see the output as

The service / requester kubernetes-demo . has been created

publish.apps/student-kubernetes-demo . created

Kubectl . application

10. Now go to the pods section again: kubectl get pods. You will see 2 pod working as mentioned as 2 replicas inside the post. yaml.

Kubectl Get Pods 2

11. Now go to services using kubectl get services ordering. You will see information related to the published service.

Service name: Experimental ruler student

Type: LoadBalancer

IP set, external IP: Here, as we posted on the local Kubernetes, you will see the external IP as localhost with port 8080.

Kubectl Get Services

12. The deployment to the Kubernetes group is now complete. We’ll go to Postman and click on the localhost URL to see if our app is working.

We will try two APIs as below:

a) POST API for creating student records

b) GET API to retrieve all students

POST API:

POST API

POST API 2

Get API:

Get API

13. Since I put some loggers inside the code, I can see those loggers being printed inside the capsules. Just type the command as follows:

kubectl get pods

kubectl . records

spring shoes

That’s it guys for this tutorial. Hope you all liked it. Happy learning!

.

Leave a Comment