How to Dockerize Spring Boot and MongoDB Project with Microservice Architecture?
A Spring Boot project will be Dockerized which uses Microservice Architecture and MongoDB.
Introduction
We will use and mention Microservice Architecture, Layered Architecture, RESTful API Design, NoSQL Database, Docker, Docker-Compose, Swagger, and more.
Requirements
- JDK (11)
- Maven (3.8.1)
- IDE (IntelliJ IDEA)
- MongoDB (5.0.3)
- Docker Desktop (20.10.11)
You can choose some different options.
GitHub Repository
Unfortunately, I cannot add the whole code. If you want to learn more about the project details you can check my GitHub.
Feel free to give stars if you enjoyed this article. I would appreciate it if you open an issue or contribute to the repository. It will always be better together!
What is Microservice Architecture?
Microservices are a distributed and loosely coupled version of monolithic architecture. It also has many benefits, but only when it is used in the right situations. Some of these benefits are independence, scalability, maintainability, and testability. Microservices should observe and apply the principles like single responsibility, loose coupling, and high cohesion.
What is NoSQL?
NoSQL is a high-performance, non-relational database with flexible data models. It is preferred when scalability, low latency, and high availability are needed. There are some types of NoSQL databases like Key-Value, Document (MongoDB), Graph, and Column-Oriented.
If you want to understand NoSQL in-depth, you should search CAP theorem and BASE approach.
Creating a Spring Boot Application
Let’s see how to create our Microservice Architecture in Spring Boot. I will use just a microservice but if you want to learn how to use multiple microservices and communication between these, contact me.
We are moving forward with Spring Initializr and applying in the following picture. I’ve used Spring Boot 2.6.2 because it was a stable version at that time.
Now we can open the downloaded project in IDE. As you can see, dependencies were not added when creating the project because I want to add the required dependencies using Maven Dependency Management manually and create our package structure subsequently.
The module was added into the microservices-project
main project folder for using Microservice Architecture as you see below. We are going to use Layered Architecture in our microservice, let’s see how it was implemented.
Layered Architecture, is a well-established software application architecture that separates the responsibilities. It is divided into 3 main headings that try to explain our project.
- Presentation Layer: The purpose of the Presentation Layer is to display and collect information from the client.
API
package corresponds to Presentation Layer. - Business Layer: The purpose of the Business Layer which is the heart of the project contains business codes, rules, and logic that are implemented here.
business
package corresponds to Business Layer. - Persistence Layer: It transforms the business object into database domain models and contains Data Access Objects (DAO).
dataAccess
packages correspond to Persistence Layer. - Data Layer: The purpose of the Data Layer is to perform CRUD (Create, Read, Update, Delete) operations in the database.
entity
packages correspond to the Data Layer.
In addition, we could have different Layered Architecture structures. What matters is the logical separation of codes.
Let’s add main dependencies for managing all microservices dependencies in microservices-project/pom.xml
and Product Microservice dependencies in product/pom.xml
.
@SpringBootApplication
annotation includes @Configuration
, @EnableAutoConfiguration,
and @ComponentScan
which indicates a configuration class that declares one or more Bean methods. @EnableMongoRepositories
annotation required for using MongoDB repositories that indicates the Spring.
As you can see above, created Swagger which provides interface and documentation of API’s implementation methods and the main method of the project. In order to run the Application, you will use Product Microservice.
I have presented only one of the APIs which has been used in the application.
The Lombok package which configures entities has been used. @Data
annotation contains@RequiredArgsConstructor
, @Getters
, @Setters
, @ToString
, @EqualsAndHashCode
. So, we do not need to add these annotations manually because they have already been added.
@Document
annotation is used to set the collection name. If the collection does not exist, it will be created. It is called the Code First approach. @Id
annotation indicates that the field is the Primary Key of the Collection. If you need to configure any field, you can use @Field
annotation.
@Repository
annotation creates a bean for MongoRepository by Spring. Existing methods were used but we could also write our methods. @Query
annotation can also be used to specify custom queries.
@Service
annotation indicates that the business logic are located here.
Dependency Injection is providing the instances that a manager class needs instead of constructing them itself. The classes that are applied will be more loosely coupled. I prefer to use the most popular alternative of Dependency Injection techniques, Constructor Injection in between 4–9 lines.
@RestController
annotation includes @Controller
,@ResponseBody
and it handles every request that introduced for using RESTful web services. @RequestMapping
annotation is used for routing in controller classes.
As you can see, general application settings are identified under the Application Settings comment line. Database Settings and Other Settings are also identified under their comment lines. I would like to point out that other settings were added because of a bug that occurred between Spring and SpringFox.
The application is ready for running in the Product Application class. Our first API is available in Swagger or Localhost. If localhost is selected, HTTP Request should be sent correctly otherwise an error will have occurred (HTTP 405 Method Not Allowed).
The Spring Boot part has been completed. We can start the most important part of this project. I would like to explain Docker and the purpose of usage.
What is Docker?
Docker is the most popular open-source container technology. It provides; easy installation, running, testing, deploying, and maintaining of our applications. There are a lot of reasons for using Docker but the most significant reason is that the application could be used in every environment. If you want to learn Docker commands, click here. Let’s dive deeper.
Docker Image can be called a template with instructions for creating a Docker Container which is the packaged version of the application. We can create and publish our Docker Images or use other ones on the Docker Hub.
Docker Container is running or stopped version of the Docker Image and covers it. It is a structure in which we can manage runtime dependencies and provides process isolation with less resource consumption without using the virtualization of the operating system.
Dockerfile is a text document file used to specify a base image to Docker. The file name must be Dockerfile
and there is no extension. Every line in Dockerfile represents a layer.
Docker Compose is a .yml-based file that provides multiple containers that can be run and stopped with a single command. It consists of 4 main partitions which are version
, services
, networks
and volumes
.
The application will be dockerized, then Docker Compose will be created. Docker Desktop must be started during these operations.
Just to dockerize using Dockerfile, we have to replace the 7th line of the application.properties
file with the text below. It cannot be localhost anymore because the application and the database will not be running on the same host.
spring.data.mongodb.host=host.docker.internal
The application must be built for dockerizing due to the row identified /target/product-0.0.1-SNAPSHOT.jar
in Dockerfile as seen in the following code snippet. Make sure that you are on the right path (..\microservices-project
) and run the following command. After that, you will see BUILD SUCCESS
the output and a jar file will be created under the target
folder.
mvn clean install
Dockerfile must be created in the Product Module.
FROM
corresponds to the name of the base Docker Image. In this exampleopenjdk:11
is suitable.EXPOSE
determines the port address where the container is running in Docker.COPY
copies the specified files to the specified destination in the Docker Image.CMD
arranges the working order that executes the commands and parameters written in it.
Go to ..\microservices-project\product
path and run the following command for dockerizing the application. .
the dot at the end shows that it will put the image which will be created in the same folder. Here we write whatever we want the tag name after -t
.
docker build -t product-service .
We can see the product-service
image in the Images tab of Docker Desktop.
After that, the following command should be running to set up port redirection at the host.
docker run -p 8000:8000 product-service
We can see the product-service
container in the Containers/Apps tab of Docker Desktop.
busy_mendel
name has been assigned the container as the default name by Docker. Also if we want to assign a special name and run it in detached mode, the following command can be run. Detach mode means the container runs in the background and is it shown as -d
.
docker run --name=product-container -dp 8000:8000 product-service
You could make a request again from Swagger or anywhere, the application will be ready for that in the container.
If any change in the application, these processes must be repeated from the beginning. I am going to write a new article about CI/CD Pipeline to avoid this repetition.
Let’s stop the application in Docker Desktop before continuing.
version
Docker Compose version.services
include product-service and product-database.build
makes the Dockerfile run and extracts the image inproduct-service
.depends_on
makes the product-database written first run.environment
contains the variables ofapplication.properties
file because Docker does not see this file.
It is necessary to mention information for the communication between containers. The backend and the database containers have to communicate with same host. We did not define network and Docker will create default (bridge) network for these containers.
We must run the Dockerfile in the same path. The second file name is docker-compose.yml
, which is the Docker Compose file.
docker-compose -f docker-compose.yml up
As I said first, the product-database
is pulled from the specified mongo
image then the product-service
is pulled from the Dockerfile. Now the product
is running in Docker Compose!
Additional: Dockerizing without Dockerfile
Here I will just describe the easy Docker Image creation way. The application can be dockerized using the spring-boot-maven-plugin
without Dockerfile. We just need to make some additions in the part between the build tags of theproduct/pom.xml
.
As you can see below, The part inside the configuration
and executions
tags has been added. If you would like to compare the old and new versions, you can reach out here.
We will run the mvn clean install
code in the terminal. The process may take a long time than the normal build process. After this process is finished, the Docker Image is in Docker Desktop. As you know, the Docker Image can run as a Docker Container and add a Docker Compose file to this image.
Conclusion
In conclusion, we created the Spring Boot Project and use other new technologies in this article. If you like this article please do not forget to drop a comment and like. Thank you for your attention. I also want to say thanks to Bekir Can Baykal for his support.
While I am writing my articles, I assume that you know some basics. Nevertheless, if you have any questions which are related to these topics, please do not hesitate to contact me via Email or LinkedIn.