Deploying Spring Boot + MongoDB Application with Docker

In this tutorial, you will learn to design and deploy the simple Spring Boot-based application to Docker.

Overview

Docker is becoming an increasingly important tool in the DevOps process.  It allows you to package an application, along with all its dependencies into a so-called container, and then run it in any environment. We will see how to create a Docker image of the Spring Boot application and walk through the basic Docker commands.

Docker Basics

The idea behind containerization is that it simplifies and automates the deployment of applications and their dependencies. In the end, all containers are launched in the same way, regardless of what is inside.

Docker is a tool designed to make it easier to create, deploy, and run applications by using containers. Containers allow a developer to package up an application with all of the parts it needs, such as libraries and other dependencies, and ship it all out as one package.

Reason to dockerize your application:

  • Mobility: Containers can run your application anywhere irrespective of the host operating system.
  • Scalability: Multiple instances of the containerized image can be deployed on the same machine based on application/API load.
  • Faster Delivery: Docker images make it easy to put new versions of software and deploy them to production
  • Best for Microservice Architecture: Docker images are lightweight, portable, and self-contained hence best suited for next-gen cloud-native architecture.

As an example, we will develop a simple REST-based Spring Boot application and then create a Docker image based on it, and deploy a container to a local machine.

Preparation:

  • JDK 1.8
  • Intellij Idea for IDE
  • Maven
  • SpringBoot Application
  • Lombok plugin
  • Docker Desktop 

This tutorial has the following steps for better understanding:

  • Creating a Basic Spring Boot Application,
  • Building a Docker file,
  • Creating a Docker image,
  • Running the MongoDB Container,
  • Running the Spring Application Container.

Step 1: Creating a Basic Spring Boot Application

Before starting with Docker, we will create a simple REST API in the Spring Boot application. The application aims to provide us CRUD functionality via REST API with MongoDB. Later we will migrate the application execution environment and database in Docker Container.

Our application architecture will be as follow:

You can use the Spring Initializr page to create an initial project template. After importing the project into IDE, we will be creating the following sub-packages inside our main package ‘com.appsdeveloperblog.DockerTutorial‘  :

  • Config:  This package contains a configuration class with the filename ‘config.java’
  • Controller:  This package contains class ‘UserController‘ with filename ‘UserController.java’
  • Model: This package contains user POJO structure with filename ‘User.java’
  • Repository: The package contains MongoRepository interface implementation

In the end, the final project structure will look like this:

project structure

 

In the following sections, we will learn about each section in detail.

Maven Dependencies

The complete pom.xml file will be as below −

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.appsdeveloperblog.DockerTutorial</groupId>
    <artifactId>Spring-boot-custom-JSON</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>SpringBoot Docker Tutorial</name>
    <description>SpringBoot Docker Tutorial</description>

    <properties>
        <java.version>11</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

Model Class

Model package contains the POJO structure of the User object.  The complete code for the user.java file is as follows −
package com.appsdeveloperblog.Dockertutorial.model;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document
@Getter
@Setter
@AllArgsConstructor
public class User {
    @Id
    private int id;
    private String firstName;
    private String lastName;

}

Controller Class

In this class, we will be annotating it with @RestController annotation, hence it will handle our web requests like GET /users for retrieving user lists from MongoDB. The complete code for the UserController.java file is as follow −

package com.appsdeveloperblog.Dockertutorial.controller;

import com.appsdeveloperblog.Dockertutorial.model.User;
import com.appsdeveloperblog.Dockertutorial.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
public class UserController {
    @Autowired
    UserRepository userRepository;

    @GetMapping("/users")
    public List<User> list() {
        return userRepository.findAll();
    }
}

MongoRepository Class

This class extends the MongoRepository interface, as we are using MongoDB for persisting data. Hence, MongoRepository will by default provides us with generic methods like save(), findAll(), insert(), etc.
The complete code for the UserRepository.java file is as follow −

package com.appsdeveloperblog.Dockertutorial.repository;

import com.appsdeveloperblog.Dockertutorial.model.User;
import org.springframework.data.mongodb.repository.*;


public interface UserRepository extends MongoRepository<User, Integer> {
}

Config Class

The class is annotated with the @Configuration annotation, here we implement the CommandLineRunner and this class provides have methods to perform CRUD operations on the configured database and collection. We will insert two test records in our MongoDB collection at the start of the application.
The complete code for the MongoConfig.java file is as follow −

package com.appsdeveloperblog.Dockertutorial.config;


import com.appsdeveloperblog.Dockertutorial.model.User;
import com.appsdeveloperblog.Dockertutorial.repository.UserRepository;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@EnableMongoRepositories(basePackageClasses = UserRepository.class)
@Configuration
public class MongoConfig {
    @Bean
    CommandLineRunner commandLineRunner(UserRepository userRepository) {
        return strings -> {
            userRepository.save(new User(1, "Calvin", "Ryan"));
            userRepository.save(new User(2, "Bryson", "Reid"));
        };
    }
}

Resources

Inside the resources package, we will create our application.properties which will contain MongoDB connection parameters. As we will be running our MongoDB instance as a separate container hence our host will be ‘host.docker.internal‘ via which we will access the application container will access MongoDB service on another container.

spring.data.mongodb.host=host.docker.internal
spring.data.mongodb.port=27017

Step 2: Creating a Docker file

Firstly, we create a file with the name Dockerfile at the root of our project structure with the contents shown below.

FROM openjdk:11
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]

A Dockerfile is a plain text file that contains a list of commands that the Docker client runs while creating an image. Let’s go line by line to understand what each step is doing.

Step 3: Building  a Docker image

First, we will build our application locally using a maven build. It will package the application into a jar file.

mvn clean install

After receiving the build success message,  we will be build a Docker image of our application by using the below command:

docker build -t myfirst_docker_image .

Subsequently,  you should see similar output on the console window if everything goes fine.

This can also be confirmed, if the build is successful or not by using the below command. It should display the image information with the hash of the image.

docker images  | grep "myfirst"

Step 4: Running the MongoDB Container

But, before we start running our application on the Docker container. We need to run our dependent database container i.e. MongoDB as well. To set up the MongoDB container the following steps are needed.

First, we will pull the latest MongoDB image from the Docker repository using the below command.

docker pull mongo

Although, the above command will give you the latest current released image. But, if you are interested in a specific version then you can use the below command.

docker pull mongo:4.0.4

(In this example, we will stick to the latest version of MongoDB. )

It may take a moment to download the complete image, but when it is done, we have an image that is ready to use.

Next, we need to run the downloaded image. In order to run Mongo image, we use the following command:

docker run -d --name mongo-on-docker -p 27017:27017 mongo

Let understand the command a bit,

  • -d run the container in the background so that we are free to use the current terminal instance.
  • --name mongo-on-docker defines a friendly name for the container.
  • -p 27017:27017 declares that the local port 27017 is mapped to the container internal 27017 port.
  • mongo this signifies the name of the image to run

Once the container is up and running, it exposes MongoDB service on port 27017.

Step 5: Running the Spring Application Container

As we already created the docker image in step 3, now we will run the image using the below command:

docker run -d --name springapplication-on-docker -p 8080:8080 myfirst_docker_image

Once the container is up and running, it exposes port 8080 on which our spring boot service is running. We can now execute GET URL http://localhost:8080/users  either on browser or Postman.

As expected, your application will be available on http://localhost:8080/users and it successfully retrieves the list of users from MongoDB.

 

We can also view the logs for our application in docker using the following steps.

First, we need to find the container id on which our service is running.  This we can get via the following command

docker container ls -a

Now, we will execute log query

docker logs <ContainerID>

This way we can get a complete log of our application as well.

Conclusion

Although, there are many ways to create docker images. In this tutorial, we learned one of the ways to create a docker image from a simple Spring Boot project using the docker command. As a result, we learned how to run a container and tested the REST endpoint inside this image. I hope you enjoyed it. Happy learning !!


Leave a Reply

Your email address will not be published. Required fields are marked *

Free Video Lessons

Enter your email and stay on top of things,

Subscribe!