Spring boot application on kubernetes

Introduction

Kubernetes is the container orchestration tool which has gained lot of traction in the last couple of years. Kubernetes is highly scalable and can be used on bare metal, VMs and on almost all public cloud offerings

In this blog post I will demo how you can deploy a simple spring boot application packaged as a docker image to a kubernetes cluster running on your local machine using minikube. We will start by writing a small application and then will package it as a docker image and finally will deploy it on kubernetes cluster. We will expose this application using Ingress so that it is available outside the cluster.

Prerequisite to this demo

  1. You are well versed with Spring boot and have jdk and maven tooling available
  2. You have docker installed to create docker images for your application
  3. You are aware of the basic constructs and architecture of Kubernetes
  4. You have minikube installed for spinning up a kubernetes cluster

If you have all the above tooling we can proceed with the demo or else please go through the general introduction and configure your system correctly before moving forward. There are plenty of resource out there to help you in getting started with Spring Boot, Docker and Kubernetes as this is outside the scope of the tutorial.

Lets get started with the demo

Create a Spring Boot App

Go to start.spring.io and bootstrap an application with web and lombok as mandatory dependencies.

Add these two model classes. These are used for creating our response JSON message. We will be populating this response with Host details which will help us understanding from where we are getting the response.

Host Details:

@Value
@Builder
public class HostDetails {
    String hostname;	
}

Pong Message :

@Value
@Builder
public class PongMessage {
    String message;
    HostDetails host;
}

Add a ping controller as highlighted below. This controller just fetches the host details and populate our model classes with the same. We send this as a JSON response to our caller.

@CrossOrigin
@RestController
@RequestMapping(value="/ping")
public class pingController {
	
    InetAddress ip;
	
    @RequestMapping(value="", method=RequestMethod.GET)
    public ResponseEntity<PongMessage> sendPongWithHostDetails() {
        String hostname = null;
        try {
            ip = InetAddress.getLocalHost();
            hostname = ip.getHostName();
        } catch (UnknownHostException e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
        HostDetails host = HostDetails.builder()
                        .hostname(hostname)
                        .build();
	PongMessage message = PongMessage.builder()
                        .message("pong")
                        .host(host)
                        .build();
        return new ResponseEntity<>(message, HttpStatus.OK);
    }
}

Run this application locally using the below command and test if you can query localhost:8080/ping

mvn spring-boot:run

If the ping controller is working fine, package the application as a fat jar using the below command

mvn clean package

Creating a Docker image for your App

Create a docker directory within the root of your application. This directory is used to populate the docker context for our docker build command.

Switch to the above directory and create a docker file like below and copy your jar from the target directory into it.

FROM openjdk:8-jre-alpine
MAINTAINER pulgupta
COPY k8Demo-0.0.1-SNAPSHOT.jar /opt/app/lib/
ENTRYPOINT ["/usr/bin/java"]
CMD ["-jar", "/opt/app/lib/k8Demo-0.0.1-SNAPSHOT.jar"]
EXPOSE 8888

Issue this command to create a docker image. I am using my docker hub id for creating the image and tagging it to latest. Please use your docker id here. In case you do not have a docker id please create a new one at hub.docker.com

docker build . -t pulgupta/hostping:latest

Push this docker image to your docker hub account so that it is available for your Kubernetes cluster for download.

docker push pulgupta/hostping

Creating Kubernetes Artifacts

Creating service

This service is used to link our pods and route traffic to the pods available for this Service. For Ingress(created in the later section) we are required to create a service of type NodePort which will allocate a port for this service on all the nodes available in the kubernetes cluster. Also we are mapping port 80 to the port 8080, which is the port where our spring application will be running inside the pods.

apiVersion: v1
kind: Service
metadata:
  name: hostping
  labels:
    run: hostping
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    run: hostping
  type: NodePort

Creating deployments

We are creating replica set with 2 replicas which will create two pods for the image which we have specified in the containers section. We also mention the port which will be exposed outside the container.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostping
spec:
  selector:
    matchLabels:
      run: hostping
  replicas: 2
  template:
    metadata:
      labels:
        run: hostping
    spec:
      containers:
      - name: hostping
        image: pulgupta/hostping
        ports:
        - containerPort: 8080

Creating Ingress

Ingress will behave as a smart router and will redirect external traffic to our service based on the routing rules we are specifying here. As per the below rules when Ingress will see a request coming to /ping it will redirect the request to our service “hostping”.

NOTE: Enable ingress add-on for ingress to work in minikube

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: hostping
spec:
  rules:
  - http:
      paths:
      - path: /ping
        backend:
          serviceName: hostping
          servicePort: 80

Finally create all these artefacts using the below command. k8Templates is a file with all the three kubernetes artefacts as mentioned above and separated by three hyphen —. You can also create three separate files and run this command once each for Service.yaml, deployment.yaml and Ingress.yaml

kubectl create -f k8Templates

Testing your deployment

Find out the minikube ip address using the below command

minikube ip

If you have followed all the steps correctly then you will be able to query the application using the minikube ip and the path /ping for example  : http://192.168.99.100/ping

Note: If you will refresh the page again and again you will see two different hostnames. This is because in our deployment we have specified 2 replicas and thus two pods were created for this application.  These pods are hit alternatively by our service and thus we see two different hostnames.

Further action

In the next blog we will be creating a frontend app and will setup a service to service communication with our host ping app and the frontend.

Additional Resources:

Leave a comment