DEV Community

Maroun Maroun
Maroun Maroun

Posted on

Hello, K8s Spring Boot!

Let's try to build the simplest Java Spring application that runs as a pod in a Kubernetes cluster.

The full project can be found on my GitHub.

The project's structure:

├── Dockerfile
├── README.md
├── 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 our entry point:

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);
    }

}

and our controller simply returns "hello world" on the root path:

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!";
    }

}

Now let's write a Dockerfile:

FROM gradle:jdk10 as builder

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

It uses Gradle in order to build the application, and the CMD instruction runs the JAR file.

The K8s deployment is simple. It consists of a deployment and a 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

The deployment defines two replicas of the pod that will be running the container that's built from the image specified in the image attribute.

The service is of type ClusterIP (the default Kubernetes service). It gives us a service inside our cluster that other apps can access.

Creating the resources in your cluster:

kubectl create -f <yaml_file>

The resources can be visualized as follows:

+---------------------+
| hello-world-service |
|                     |
|    10.15.242.210    |
+---------O-----------+
          |
          +-------------O--------------------------O
                        |                          |
              +---------O-----------+    +---------O-----------+
              |        pod 1        |    |        pod 2        |
              |                     |    |                     |
              |     hello-world     |    |     hello-world     |
              +---------------------+    +---------------------+

Inside The Cluster

If you're using minikube for running the cluster locally, you might encounter issues (I really don't know why). But if you're running on a cloud provider, or something more "serious" than minikube, you should be able to do the following:

$ 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!

If you have any questions, please drop a comment.

Latest comments (0)