Deployment Setup for Spring Boot Apps With MongoDB and Kubernetes
In this article, we demonstrate the setup of an AngularAndSpring project to show the development setup with an in-memory MongoDB and Kubernetes setup for deployment. The goal for the development setup is to have a Spring Boot app that can be run without a local MongoDB installation and be developed with fast restarts. The goal for the Deployment Setup is to build a Docker image of the project and to run it in a Kubernetes setup with a MongoDB image to have horizontal scalability of the front-end.
Development Setup
To get the in-memory MongoDB, this profile has to be added to the pom.xml:
<profile>
<id>standalone</id>
<activation>
<property>
<name>docker</name>
<value>!true</value>
</property>
</activation>
<dependencies>
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>
</dependencies>
</profile>
This profile checks the property 'docker,' and if it not found (the default), it adds the dependency of the embedded MongoDB. The Project can just be started and have a MongoDB available on the development computer.
The property file looks like this:
security.jwt.token.secret-key=secret-key1234567890abcdefg
security.jwt.token.expire-length=86400000
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=test
It sets the default values for MongoDB that will be overwritten in the Deployment Setup.
@Configuration
public class SpringMongoConfig extends AbstractReactiveMongoConfiguration {
private static final Logger log = LoggerFactory.getLogger(ScheduledTask.class);
@Value("${spring.data.mongodb.host}")
private String mongoHost;
@Value("${spring.data.mongodb.port}")
private String mongoPort;
@Value("${spring.data.mongodb.database}")
private String mongoDB;
@Override
protected String getDatabaseName() {
return mongoDB;
}
@Override
public MongoClient reactiveMongoClient() {
String myHost = System.getenv("MONGODB_HOST");
log.info("MONGODB_HOST="+myHost);
return MongoClients.create("mongodb://"+(myHost==null ? mongoHost : myHost)+":"+mongoPort);
}
}
In lines 5-12, the config of
is read from the application.properties.
In lines 20-24, the environment variable is read and its value used for the host of the MongoDB, if it is set.
In the development setup, the 'MONGODB_HOST' environment variable does not exist and the defaults of the properties file are used. The Kubernetes setup sets the environment variable and the MongoDB of the Kubernetes setup is used.
That is all that is needed for the development setup.
Deployment Setup
To avoid the setup of the AngularAndSpring Project and the MongoDB on the server, Docker images are used. To manage the Docker images, Kubernetes is used. That way, the images can be deployed on a cloud with Kubernetes support, and the stateless frontend is scalable. In this example, the Minikube project is used to have a local Kubernetes distribution on the computer.
Create the Docker image
To create the Docker image, the Maven build has to be executed with the command 'mvn clean install -Ddocker=true.' That activates the following profile:
<profile>
<id>docker</id>
<activation>
<property>
<name>docker</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.4</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
<tag>${project.version}</tag>
<buildArgs>
<JAR_FILE>${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
This profile does not add the in-memory MongoDB and creates the Docker image of the Spring Boot Jar. Then, the image has to be pushed to the Docker Repository, or the image available at the public repo can be used.
The Kubernetes Setup
To set up the Minikube distribution on a computer, there is documentation for the different Operating Systems. You need Minikube and kubectl.
Volume
To persist the data of MongoDB, a Volume is needed. This is kubMongoVolume.yaml.
kind: PersistentVolume
apiVersion: v1
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
capacity:
storage: 1Gi
hostPath:
path: /data/mongo1
type: DirectoryOrCreate
This file sets up a persistent volume to store the data in. The accessMode
means it can be used by one user, and the hostPath
is set to the /data
directory of Minikube that is persisted on the hard disk. The type is needed to create the directory if it does not exist yet.
VolumeClaim
The VolumeClaim
requests the storage for MongoDB. The following is kubMongoVolumeClaim.yaml.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongo-pv-claim
labels:
app: mongopv
spec:
accessModes:
- ReadWriteOnce
storageClassName: manual
resources:
requests:
storage: 1Gi
VolumeClaim
requests the storage that was provided by the Volume. There are other types of storage that can be used by more than one VolumeClaim
.
MongoDB Deployment
This deployment has the setup for the MongoDB Docker image in Minikube. This is kubMongo.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb
labels:
appdb: mongodb
spec:
replicas: 1
selector:
matchLabels:
appdb: mongodb
template:
metadata:
labels:
appdb: mongodb
spec:
containers:
- name: mongodb
image: mongo:3.6.6
ports:
- containerPort: 27017
volumeMounts:
- name: hostvol
mountPath: /data/db
volumes:
- name: hostvol
persistentVolumeClaim:
claimName: mongo-pv-claim
The spec has the Docker config for the MongoDB image and the volume of the volume claim.
Line 19 is the Docker image of MongoDB.
Line 21 is the port that is exposed.
Lines 23-24 are the connection of the volume to the image path. The path "/data/db" is the path where MongoDB stores its files, and it is mounted on the persistent volume.
Lines 26-28 are the connection of the volume to the persistent volume claim
MongoDB Service
This service has the setup of the service inside Minikube for MongoDB. This is kubMongoService.yaml.
apiVersion: v1
kind: Service
metadata:
name: mongodb
labels:
app: mongodb
spec:
ports:
- port: 27017
protocol: TCP
selector:
appdb: mongodb
This has the setup to expose the MongoDB service in Minikube.
AngularAndSpring Deployment
This deployment has the setup of the Docker image of AngularAndSpring. This is kubApp.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
name: angularandspring
labels:
app: angularandspring
spec:
replicas: 1
selector:
matchLabels:
app: angularandspring
template:
metadata:
labels:
app: angularandspring
spec:
containers:
- name: angularandspring
image: angular2guy/angularandspring:latest
env:
- name: MONGODB_HOST
value: mongodb
ports:
- containerPort: 8080
The spec part has the setup of the Docker image of AngularAndSpring.
In line 19, there is an image from DockerHub.
In lines 21-22, we see the setting of the "MONGODB_HOST" environment variable to the DNS of the DB. Kubernetes sets the DNS name of the MongoDB deployment to "mongodb" so that the Mongo Path in the Spring Boot configuration works.
In line 24, the HTTP port of the Project is exposed.
AngularAndSpring Service
The service of AngularAndSpring sets up the port of the Project. This is kubAppService.yaml.
apiVersion: v1
kind: Service
metadata:
name: web-service
labels:
run: web-service
spec:
type: NodePort
ports:
- port: 8080
protocol: TCP
selector:
app: angularandspring
The spec exposes the port 8080 of the AngularAndSpring deployment.
Run the Setup
To run the setup, the YAML files need to be run with the kubectl command. If a shell is available, this file can be used minikubeSetup.sh.
#!/bin/sh
kubectl create -f ./kubMongoVolume.yaml
kubectl create -f ./kubMongoVolumeClaim.yaml
kubectl create -f ./kubMongo.yaml
kubectl create -f ./kubMongoService.yaml
kubectl create -f ./kubApp.yaml
kubectl create -f ./kubAppService.yaml
kubectl get services
minikube ip
First, the Minikube has to be started with the command "minikube start." Then, the commands need to be executed. Then, the commands "kubectl get services" and "minikube ip" will show an output like this:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 10d
mongodb ClusterIP 10.109.101.39 <none> 27017/TCP 10d
web-service NodePort 10.105.201.74 <none> 8080:31810/TCP 10d
192.168.99.100
To access the AngularAndSpring Project, the URL for the browser is:
http://192.168.99.100:31810/
This represents the IP of line five and the port that is mapped to 8080 of line 4.
The quotes are requested by a timer method. That means the project takes a few seconds to initialize itself and show the first set of quotes.
Conclusion
This setup enables easy development of Spring Boot Apps with reactive features that are available with MongoDB. The deployment setup enables the easy deployment of the AngularAndSpring Project and the MongoDB on a Kubernetes cluster. The front-end is easily scalable. And, because it is stateless, the MongoDB back-end would need a separate setup for further scalability. That makes a deployment in a cloud that supports Kubernetes easy. That way, the reactive features of Spring can be used without the effort of setting up a local DB for development or deployment.