An example of deploying a Spring Boot application to Kubernetes
The translation of the article was prepared especially for the students of the course “Spring Framework Developer”…
Let’s create a basic Spring Boot application that will run on a Kubernetes cluster.
Project structure
├── Dockerfile
├── build.gradle
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── k8s
│ └── depl.yaml
├── settings.gradle
└── src
└── main
└── java
└── hello
├── App.java
└── HelloWorldCtrl.java
App.java is the entry point for the application:
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
The above code is a minimal Spring Boot application.
The HelloWorldCtrl.java file contains a simple controller that maps the root (“/”) to the index method, which returns a welcome string:
package hello;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
public class HelloWorldCtrl {
@RequestMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
}
Building the application
I am using Gradle to build. The build.gradle file is also minimalistic:
plugins {
id 'org.springframework.boot' version '2.3.3.RELEASE'
id 'io.spring.dependency-management' version '1.0.8.RELEASE'
id 'java'
}
group = 'com.test'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
}
Create K8s resources
To deploy to K8s, we need a Docker image. Let’s add the following lines to the Dockerfile:
FROM gradle:jdk10
COPY --chown=gradle:gradle . /app
WORKDIR /app
RUN gradle build
EXPOSE 8080
WORKDIR /app
CMD java -jar build/libs/gs-spring-boot-0.1.0.jar
Steps in our Dockerfile:
- copying the project to / app
- building the project using Gradle
- launching the application using the result of the previous step
docker build -t marounbassam/hello-spring .
docker push marounbassam/hello-spring
The K8s manifest file is simple too. It consists of a deployment (Deployment) and service (Service):
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 2
template:
metadata:
labels:
app: hello-world
visualize: "true"
spec:
containers:
- name: hello-world-pod
image: marounbassam/hello-spring
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
labels:
visualize: "true"
name: hello-world-service
spec:
selector:
app: hello-world
ports:
- name: http
protocol: TCP
port: 8080
targetPort: 8080
type: ClusterIP
Deployment defines two pod replicas that will run the container created from the image specified in the image attribute.
Service has ClusterIP type (default service type). It provides within the cluster the ability to connect to us for other applications.
We create resources in the cluster:
kubectl create -f <yaml_file>
Resources can be visually represented as follows:
Inside the cluster
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-world-5bb87c95-6h4kh 1/1 Running 0 7h
hello-world-5bb87c95-bz64v 1/1 Running 0 7h
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world-service ClusterIP 10.15.242.210 <none> 8080/TCP 5s
kubernetes ClusterIP 10.15.240.1 <none> 443/TCP 7h
$ kubectl exec -it hello-world-5bb87c95-6h4kh bash
$ (inside the pod) curl 10.15.242.210:8080
$ (inside the pod) Greetings from Spring Boot!
We can see that the server has started and is running inside the pods. You can also set up a service like LoadBalancer (depending on your cloud provider) and access the application from outside the cluster.
Conclusion
We created a simple Spring Boot application, launched it in a Docker container in the K8s pod, which is managed through K8s deployment and is available through the service.
We now have simple load balancing for the two created pods, and easy scalability according to the needs of the application.