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.

 

 

 

 

Top