Implementing Kubernetes liveness, Readiness and Startup probes with Spring Boot Microservice Application?


Maintaining a healthy kubernetes cluster is really challenging especially if you have not configured the Liveness, Readiness and Startup Probes correctly for your containers deployed under kubernetes containers.

If I have to put in a simple way -

Liveness probes - It is responsible for restarting your container, if it senses a deadlock. Readiness probes - This probe will tell when the container is ready to start traffic. Startup probes - It tells when the container application has started.

But who is communicating with these probes? - The answer is kubelet.

Now the next question comes: what is kubelet? - Kubelet is a Node Agent which acts like caretaker for containers running inside Kubernetes Pod.

If kubelet is caretaker then it should have some mode of communication with containers, which are running inside kubernetes POD and these mode of communication we call it Liveness, Readiness and Startup probes

In this blog post we are going to take an Example of Spring Boot Microservice application and we are going to define Liveness, Readiness and Startup probes.

Here are our steps for implementing Liveness, Readiness and Startup probes -

  1. Create an Spring Boot Microservice Application
  2. Write kubernetes deployment.yaml and service.yaml
  3. Define Liveness probe inside deployment.yaml
  4. Define Readiness probe inside deployment.yaml
  5. Define Startup probe inside deployment.yaml
  6. Deploy both deployment.yaml as well as service.yaml
  7. Verify the application

1. Create an Spring Boot Microservice Application

(*Note - If your application stack is different and you note using Spring Boot Application then you can skip this part and directly jump to probes configuration steps.)

1.1 Setup spring boot using Spring Initializr

Before we start implementing the probes, the first important step we need to do is create a Spring Boot application. So head over to Spring Initializr and create your basic Spring Boot Microservice Project.

Here is the screenshot which I have taken from while setting up the project details of my Spring Boot application. You can customize the details as per your need.

1.2 Import the Spring Boot Project in your favorite IDE

Now after configuring your Spring Boot Project you can import the project into your favorite IDE. After importing your project into your favorite IDE we can start writing our first microservice.

Here is an Example Java class containing Hello World microserve

 1package com.jhooq.Jhooqk8s.ws;
 2
 3import org.springframework.web.bind.annotation.GetMapping;
 4import org.springframework.web.bind.annotation.RestController;
 5
 6@RestController
 7public class HelloWorldMicroservice {
 8
 9    @GetMapping("/hello")
10    public String hello() {
11        return "Hello - Foo Bar!";
12    }
13}

For this spring boot application project we are using Gradle as our preferred build tool. You can build the complete project using the following command -

1./gradlew build

Let’s run the Spring Boot Microservice Application and test the rest end point by accessing it.

Here is the command for running the application -

1java -jar Jhooq-k8s-0.0.1-SNAPSHOT.jar

For testing you can use the following URL for verifying the rest endpoint -

1curl http://localhost:8080/hello

1.3 Containerize spring boot application using Docker and Push it to Docker Hub

After implementing the microservice we can create a Docker container Image and Push the image to Docker Hub so that later on we can use the same Docker image to deploy inside the kubernetes container.

Let’s first create a Dockerfile -

1FROM openjdk:8-jdk-alpine
2ARG JAR_FILE=build/libs/*.jar
3COPY ${JAR_FILE} app.jar
4ENTRYPOINT ["java","-jar","/app.jar"]

Now build and tag docker image using the following command -

1docker build -t jhooq-k8s-springboot .
2
3docker tag jhooq-k8s-springboot rahulwagh17/kubernetes:jhooq-k8s-springboot

And finally push the Spring boot Docker image to Docker Hub

1docker push  rahulwagh17/kubernetes:jhooq-k8s-springboot

(*Note - I have already created any docker hub repository with the name rahulwagh17/jhooq-k8s-springboot)


2. Write kubernetes deployment.yaml and service.yaml

In the previous step we have prepared the Docker container image and pushed the same docker container image to Docker Hub.

Now after that we need to create kubernetes deployment.yaml and kubernetes service.yaml.

2.1 deployment.yaml

There few things which you should always keep in mind while creating your deployment.yaml configurations

  1. Docker image name - rahulwagh17/kubernetes:jhooq-k8s-springboot
  2. Port - 8080
  3. matchLabels.app - jhooq-springboot

If your docker image name is incorrect then you will not be able to deploy your docker container inside the kubernetes cluster. Please refer to this article on how to troubleshoot kubernetes deployment errors

Here is the deployment.yml

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4name: jhooq-springboot
 5spec:
 6replicas: 3
 7selector:
 8matchLabels:
 9app: jhooq-springboot
10template:
11metadata:
12labels:
13app: jhooq-springboot
14spec:
15containers:
16- name: springboot
17image: rahulwagh17/kubernetes:jhooq-k8s-springboot
18ports:
19- containerPort: 8080
20env:
21- name: PORT
22value: "8080"

2.2 service.yaml

The next kubernetes manifest we need is service.yaml and here we are going to use the same matchLabels.app which we have defined in deployment.yaml .i.e. - matchLabels.app - jhooq-springboot

Here is the service.yaml -

 1apiVersion: v1
 2kind: Service
 3metadata:
 4name: jhooq-springboot
 5spec:
 6type: NodePort
 7ports:
 8- port: 80
 9targetPort: 8080
10selector:
11app: jhooq-springboot

3. Define Liveness probe inside deployment.yaml

Alright if you reached here which means you have your application ready to be deployed inside kubernetes cluster and now you want to add the liveness probe to it.

For creating liveness probe you need to have following -

  1. Port - 8080
  2. path - /hello
  3. initialDelaySeconds - 15
  4. periodSeconds - 10

So in our example we are running spring boot application on port - 8080 the microservice service endpoint path is /hello.

We have also added an initialDelaySeconds - 15 because we want the first Liveness check to be performed after the first 15 seconds.

There is one more property which we have added: periodSeconds - 10 which will be responsible for verifying the liveness of the application every 10 seconds.

Here is an updated deployment.yaml -

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: jhooq-springboot
 5spec:
 6  replicas: 2
 7  selector:
 8    matchLabels:
 9      app: jhooq-springboot
10  template:
11    metadata:
12      labels:
13        app: jhooq-springboot
14    spec:
15      containers:
16        - name: springboot
17          image: rahulwagh17/kubernetes:jhooq-k8s-springboot
18
19          resources:
20            requests:
21              memory: "128Mi"
22              cpu: "512m"
23            limits:
24              memory: "128Mi"
25              cpu: "512m"
26
27          ports:
28            - containerPort: 8080
29          livenessProbe:
30            httpGet:
31              path: /hello
32              port: 8080
33            initialDelaySeconds: 15
34            periodSeconds: 10
35          env:
36            - name: PORT
37              value: "8080"

4. Define Readiness probe inside deployment.yaml

Now after adding the liveness probe in Step no 3 let’s add Readiness probe into the same deployment.yaml.

(Note - For readiness probe we also need to define the same number of config parameters)

Here are few config parameters which you need to define for Readiness probe -

  1. Port - 8080
  2. path - /hello
  3. initialDelaySeconds - 15
  4. periodSeconds - 10

Here is the updated deployment.yaml after adding the readiness probe -

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: jhooq-springboot
 5spec:
 6  replicas: 2
 7  selector:
 8    matchLabels:
 9      app: jhooq-springboot
10  template:
11    metadata:
12      labels:
13        app: jhooq-springboot
14    spec:
15      containers:
16        - name: springboot
17          image: rahulwagh17/kubernetes:jhooq-k8s-springboot
18
19          resources:
20            requests:
21              memory: "128Mi"
22              cpu: "512m"
23            limits:
24              memory: "128Mi"
25              cpu: "512m"
26
27          ports:
28            - containerPort: 8080
29
30          readinessProbe:
31            httpGet:
32              path: /hello
33              port: 8080
34            initialDelaySeconds: 15
35            periodSeconds: 10
36
37          livenessProbe:
38            httpGet:
39              path: /hello
40              port: 8080
41            initialDelaySeconds: 15
42            periodSeconds: 10
43          env:
44            - name: PORT
45              value: "8080"
46

5. Define Startup probe inside deployment.yaml

As the name suggests it helps you to determine whether an application has started or not. Let us take an example where an application takes around 10 minutes to startup. So if you have configured the liveness probe with an initialDelaySeconds of 15 seconds then liveness probe will always assume that application is in deadlock state because it takes 10 minutes to finish its first initialization which will always be greater than 15 seconds of liveness probe.

So to overcome this situation, a startup probe has been introduced in the kubernetes ecosystem. While defining the startup probe you should always pay attention to the following configuration properties -

  1. path - /hello
  2. port - 8080
  3. failureThreshold - 30
  4. periodSeconds - 20

Considering the above parameters the startup probe will take 30*20 = 600 Seconds which is 10 minutes. So once the 10 minutes are over and the startup probe succeeds then the liveness probe takes over.

Here is an updated deployment.yaml with startup probe -

 1apiVersion: apps/v1
 2kind: Deployment
 3metadata:
 4  name: jhooq-springboot
 5spec:
 6  replicas: 2
 7  selector:
 8    matchLabels:
 9      app: jhooq-springboot
10  template:
11    metadata:
12      labels:
13        app: jhooq-springboot
14    spec:
15      containers:
16        - name: springboot
17          image: rahulwagh17/kubernetes:jhooq-k8s-springboot
18
19          resources:
20            requests:
21              memory: "128Mi"
22              cpu: "512m"
23            limits:
24              memory: "128Mi"
25              cpu: "512m"
26
27          ports:
28            - containerPort: 8080
29
30          readinessProbe:
31            httpGet:
32              path: /hello
33              port: 8080
34            initialDelaySeconds: 15
35            periodSeconds: 10
36
37          livenessProbe:
38            httpGet:
39              path: /hello
40              port: 8080
41            initialDelaySeconds: 15
42            periodSeconds: 10
43
44          startupProbe:
45		    httpGet:
46		      path: /hello
47		      port: 8080
48		    failureThreshold: 30
49		    periodSeconds: 20
50
51          env:
52            - name: PORT
53              value: "8080"

6. Deploy both deployment.yaml as well as service.yaml

Now after preparing the deployment.yaml, service.yaml and setting up liveness, readiness, startup probe let us deploy the application inside the kubernetes cluster.

6.1 Apply the deployment configuration

Applying the deployment configuration is very easy inside the kubernetes cluster and it can be done using kubectl command -

1kubectl apply -f deployment.yaml

Verify the deployment by running the following command -

1kubectl get deployments
2
3NAME   	        READY   UP-TO-DATE   AVAILABLE   AGE
4jhooq-springboot   1/1                 1                     1              5h20m

6.2 Apply the service configuration

As we have applied the deployment configuration, similarly we can apply the service configuration also -

1kubectl apply -f service.yaml

Verify the deployed services using the following kubectl command -

1kubectl get service
2
3NAME           TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
4jhooq-springboot   NodePort   10.233.5.144   1.1.1.1       8080:31901/TCP   2s
5kubernetes     ClusterIP      10.233.0.1     <none>        443/TCP          28h

Great, you have made successful deployment using Liveness, Readiness and Startup probe.


7. Verify the application

At last you verify the microservice by accessing the cluster ip and port. The Cluster IP you will get from kubectl get service

Now you can curl the URL -

1curl http://10.233.5.144:31901/hello

The output should return - Hello - Foo Bar!


Other articles on Devops -

  1. Part-1 : Setup kubernetes on Ubuntu
  2. Part-2 : Setup Kubernetes on CentOs
  3. Part-3 : Setup HA Kubernetes Cluster with Kubespray
  4. Part-4 : Setup HA Kubernetes with Minikube
  5. Part-5 : Setup Kubernetes Dashboard for local kubernetes cluster
  6. Part-6 : Setup Kubernetes Dashboard On GCP(Google Cloud Platform)
  7. Part-7 : How to use Persistent Volume and Persistent Volume Claims in Kubernetes
  8. Part-8 : Deploy Spring Boot Microservice on local Kubernetes cluster
  9. Part-9 : Deploy Spring Boot Microservice on Cloud Platform(GCP)
  10. Part-10 : Setting up Ingress controller NGINX along with HAproxy inside Kubernetes cluster
  11. Part-11 : CI/CD Kubernetes | Setting up CI/CD Jenkins pipeline for kubernetes
  12. Part-12 : kubectl export YAML | Get YAML for deployed kubernetes resources(service, deployment, PV, PVC….)
  13. Part-13 : How to setup kubernetes jenkins pipeline on AWS?