Deploy React, Spring Boot & MongoDB Fullstack application on Kubernetes

unsplash-logoKeith Misner

In this post we will discuss how to Deploy Full stack application on Kubernetes. We will build small Student CRUD application using React as Front end, Spring Boot as back end and MongoDB as persistance layer and we also configure PersistentVolumeClaim.

The code for this post is available on Github here

Prerequisites

To Follow along this post, You need to have minikube and kubectl installed on your system. Basic knowledge of Docker,Kubernetes & Spring Boot is needed.

The sample application that we will be deploying on Kubernetes allows user to perform CRUD operations and the final deployment structure will be below.

let’s start

Step 1 : Deploy a React application on Kubernetes

The React app is created by create-react-app and then docker image is available on Ducker hub. You can also this image to follow along docker pull nirajsonawane/student-app-client

Deployment configuration

student-app-client-deployment File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: apps/v1
kind: Deployment
metadata:
name: student-app-client
spec:
selector:
matchLabels:
app: student-app-client
replicas: 1
template:
metadata:
labels:
app: student-app-client
spec:
containers:
- name: student-app-client
image: nirajsonawane/student-app-client
imagePullPolicy: Always
ports:
- containerPort: 80

Deployments in Kubernetes is declarative way of creating and updating pods. In above configurations we created student-app-client deployment indicated by name, with 1 number of replicas. The containers sections provides details about Which & How the containers should get created.

Service configuration

student-app-client-service File
1
2
3
4
5
6
7
8
9
10
11
12
apiVersion: v1
kind: Service
metadata:
name: student-app-client-service
spec:
selector:
app: student-app-client
ports:
- port: 80
protocol: TCP
targetPort: 80
type: ClusterIP

Service in Kubernetes is way to expose application running on a set of Pods (Deployments) as network service. The above configurations creates a new Service object named student-app-client-service, which targets TCP port 80 on any Pod with the app=student-app-client label. Kubernetes ServiceTypes allow you to specify what kind of Service you want. The default is ClusterIP. Please Check the documentation for more details.

let’s deploy it on our local Kubernetes cluster
Start minikube minikube start

Check minikube status minikube status

Apply deployment and service for client kubectl apply -f <file-name.yaml>

Tip: If you want to check if client pod is getting correctly deployed and want to access URL, Change the service type to NodePort and then run
minikube service student-app-client-service

Step 2 : Deploy MongoDB persistance layer on Kubernetes

For Managing storage Kubernetes PersistentVolume subsystem provides API which defines how storage is provided and how it is consumed. For this we need to create two kubernetes resources

A PersistentVolume (PV) is a piece of storage in the cluster that has been provisioned by an administrator or dynamically provisioned using Storage Classes.
lifecycle of PV is independent of any individual Pod that uses the PV. In simple words PV are user-provisioned storage volumes assigned to a Kubernetes cluster.

A PersistentVolumeClaim (PVC) is a request for storage by a user that deployment needs. It is similar to a Pod. Pods consume node resources and PVCs consume PV resources.

In order to deploy the the database component we need to define below resource configurations :

  1. PersistentVolumeClaim
  2. Deployment
  3. Service

PersistentVolumeClaim

PersistentVolumeClaim config File
1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongo-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 256Mi

The access modes are:
ReadWriteOnce – the volume can be mounted as read-write by a single node
ReadOnlyMany – the volume can be mounted read-only by many nodes
ReadWriteMany – the volume can be mounted as read-write by many nodes

Deployment

Deployment Config File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongo
spec:
selector:
matchLabels:
app: mongo
template:
metadata:
labels:
app: mongo
spec:
containers:
- name: mongo
image: mongo:3.6.17-xenial
ports:
- containerPort: 27017
volumeMounts:
- name: storage
mountPath: /data/db
volumes:
- name: storage
persistentVolumeClaim:
claimName: mongo-pvc

Deployment is requesting volume defined by claim Name mongo-pvc

Service

Service Config File
1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Service
metadata:
name: mongo
spec:
selector:
app: mongo
ports:
- port: 27017
targetPort: 27017

let’s apply all these new configurations.
Apply PersistentVolumeClaim , deployment and service for MongoDB kubectl apply -f <file-name.yaml>

Step 3 : Deploy Spring Boot Backend API on Kubernetes

Our Backend api is simple spring boot application and it is using doing CRUD using MongoRepository complete code is available on Github here

Spring boot app is dockerized and docker image is available docker hub. docker pull nirajsonawane/student-app-api:0.0.1-SNAPSHOT
Deployment

API Deployment Config File
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: apps/v1
kind: Deployment
metadata:
name: student-app-api
spec:
selector:
matchLabels:
app: student-app-api
replicas: 1
template:
metadata:
labels:
app: student-app-api
spec:
containers:
- name: student-app-api
image: nirajsonawane/student-app-api:0.0.1-SNAPSHOT
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: MONGO_URL
value: mongodb://mongo:27017/dev

in above yaml file The env: is used to define environment variables for the POD. Our API expects MONGO_URL for configuration of spring.data.mongodb.uri
application.properties
1
spring.data.mongodb.uri=${MONGO_URL:mongodb://localhost:27017/dev}

Now let’s talk about MONGO_URL.

mongodb url is configured like mongodb://someHost:27017/dev so what is mongo in our url? mongo is name defined in service config file of mongo.
Pods within a cluster can talk to each other through the names of the Services exposing them.

Service

Service Config File for API
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Service
metadata:
name: student-app-api
spec:
selector:
app: student-app-api
ports:
- port: 8080
protocol: TCP
targetPort: 8080

Apply deployment and service for API kubectl apply -f <file-name.yaml>

Step 4 : Deploy Ingress and connect frontend to backend

Ingress is an API object that manages external access to the services in a cluster.

Ingress Resource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.k8s.io/v1beta1 # for versions before 1.14 use extensions/v1beta1
kind: Ingress
metadata:
name: student-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /?(.*)
backend:
serviceName: student-app-client-service
servicePort: 80
- path: /api/?(.*)
backend:
serviceName: student-app-api
servicePort: 8080

We can define different HTTP rule in ingress configuration. For our application we have configured two rules in backend section. A backend is a combination of Service and port names as described in the Service doc. HTTP (and HTTPS) requests to the Ingress that matches the host and path of the rule are sent to the listed backend.

Note While making call to backend API from react client we are prefixing request with api and then redirecting request to student-app-api thro our Ingress. We can also use service-name for direct making call to backend api.

lets deploy the final resource.
Fist we need to enable ingress by running minikube addons enable ingress and then ‘kubectl apply -f student-app-ingress.yaml’

let’s try to access the application from minikube ip

The code for this post is available on Github here

Share Comments