Building a Spring Boot microservices monorepo project with docker-compose

Marcelo Soares
4 min readAug 9, 2020

If you are a developer and have already needed to build applications that need old and discontinued environments, you have certainly resorted to the docker to solve this problem. I usually say that Docker is the best invention of the decade. Often, we are unable to update our applications at the same speed as languages ​​and frameworks release updates.

In this post, I will present an approach that consists of using a docker container to compile a stack of Spring Boot microservices and then run all microservices using docker-compose. I recommend you download the project used in this post on Github for a better understanding.

If you want to understand more about the microservices project, visit my post Microservices architecture with shared database.

The approach uses a combination of technologies to create an automatic build and deploy mechanism for a stack of microservices, without the machine having to have java or maven installed, since everything is done inside a container.

Project structure

We will use a single monorepo repository for all microservices, so our project is structured as follows:

netflix
netflix-api-gateway
pom.xml (jar)
netflix-category-microservice
pom.xml (jar)
netflix-config
pom.xml (jar)
netflix-data
pom.xml (jar)
netflix-movie-microservice
pom.xml (jar)
netflix-service-discovery
pom.xml (jar)
netflix-user-microservice
pom.xml (jar)
pom.xml (pom)

Basically, there is a parent project at the root, defined as pom packaging. Each microservice is a maven project that is inserted as a module of the parent project.

pom.xml

Building microservices

Our first step is to create a container to compile all microservices at once. We need to do this because if we put each microservice to be compiled separately inside its own container, maven would download the same dependencies to the local repository multiple times. This means that the same dependencies would be downloaded to the local repository from within the container of each project, making the compilation process very time-consuming.

To create the “compiler image”, we will create a Dockerfile file at the root of the project and add a shell script file as an entry point. The parent image used is the official maven with openjdk-8.

In the entrypiont.sh file, we only access the directory defined in WORKDIR and execute the mvn package command to build the projects.

Create a shell script file to group some commands in order to make the build process easier. The deploy.sh file has a case statement with a code block for building the application and another for running the application. For the first case, a docker image is built and then the microservices-compiler container is created from it. After all microservices have been built, the container and image are deleted. Notice in the docker run command that a volume is created from the current directory to the container’s working directory.

When the deploy.sh file receives build as a parameter, it will build the image, create the container, and compile the projects due to mvn package command in entrypoint.sh. The files compiled inside the container will also be visible outside, since the volume was created for the current project directory.

The entry point for executing deploy.sh is an instruction to be executed by the make utility. For this, we will create a Makefile file at the root of the project and define two rules. A rule called build that executes deploy.sh file passing build as an argument and another rule called run that executes the same file passing run as an argument.

After running the make build command, notice that .jar files have been added to the target directory for each project. Remember these files were generated inside the container.

Running microservices

After compiling the entire stack, it’s time to run the microservices. To do this, simply type make run. Make will execute the file deploy.sh passing run as argument. It will use docker-compose to build the stack. Take a look at the deploy.sh file again to understand what I’m talking about.

Let’s create the docker-compose.yml file at the root of the project. The docker-compose will build the image of each microservice according to its respective Dockerfile.

The Dockerfile file for each microservice is very simple. Basically, we take the .jar files compiled by the compiler container and copy them into their respective execution container.

Since microservices depend on others for their correct execution, checks are made in the entrypoint.sh file.

To see the result of it all, follow these steps.

git clone https://github.com/marcelohweb/netflix-microservices
cd netflix-microservices
make build
make build result
make run
make run result

You can view the running containers using the docker ps command or using a visualization tool such as Portainer.

You can use this approach in a continuous integration tool such as Jenkins or Gitlab.

If you want to understand more about the application developed for this experiment, visit my post:

https://medium.com/@marceloh.web/spring-boot-microservices-architecture-using-shared-database-69312a968530

Enjoy it!

--

--