Home > Software engineering >  How to organize multi-stage Dockerfiles for multi-module microservices with common modules
How to organize multi-stage Dockerfiles for multi-module microservices with common modules

Time:11-23

I have a gRPC microservices project with following structure:

- common (common protobuf definitions)
- microservices
  - ms1
    ..
  - msN

Now I want to add multi stage Dockerfiles for each microservice. The problem is that I have this common module which I need to build the rest of the projects. I can't reference the sources outside the microservice project in Dockerfile.

So the only posibility I see is to have one Dockerfile in the root folder that builds all the images:

FROM maven:3.8.6-eclipse-temurin-17 AS builder
COPY ./ /usr/app
RUN mvn -f /usr/app/pom.xml clean package


FROM eclipse-temurin:17-jre-alpine
COPY --from=builder /usr/app/microservices/ms1/target/ms1-1.0-SNAPSHOT.jar /usr/app/ms1-1.0-SNAPSHOT.jar
ENTRYPOINT ["java", "-jar", "/usr/app/ms1-1.0-SNAPSHOT.jar"]

But still I have to build all the project in builder image. One other option I see is to create separate Docker images for builder and then referencing it inside of the microservice Dockerfile by tag. But how can I trigger rebuild for builder image when building microservice image.

Are there any other options? Which one should I use?

CodePudding user response:

We can use a multistage dockerfile with arguments (docs.docker.com) and maven's --also-make command line option (maven.apache.org):

FROM maven:3.8.6-eclipse-temurin-17 AS builder
ARG RELATIVE_PATH_TO_ADAPTER_MODULE # e.g. service/ms1
COPY ./ /usr/app

# specify the specific project to build via "-pl", we could also use "-f /usr/app/${PATH_TO_ADAPTER_MODULE}/pom.xml"
# we specify --also-make to also build the dependencies
RUN mvn -pl /usr/app/${PATH_TO_ADAPTER_MODULE} --also-make clean package

FROM eclipse-temurin:17-jre-alpine
ARG RELATIVE_PATH_TO_ADAPTER_MODULE # e.g. service/ms1
COPY --from=builder /usr/app/${RELATIVE_PATH_TO_ADAPTER_MODULE}/target/*.jar /usr/app/service.jar
ENTRYPOINT ["java", "-jar", "/usr/app/service.jar"]

Should the target-directory contains more than one .jar-file, we can exclude all unwanted .jar-files through a .dockerignore-file (docs.docker.com), e.g. in the module's root directory.

We can then build a particular microservice by calling docker build with --build-arg (docs.docker.com)

docker build --build-arg RELATIVE_PATH_TO_ADAPTER_MODULE=services/ms1 --tag services/ms1 .
docker build --build-arg RELATIVE_PATH_TO_ADAPTER_MODULE=services/ms2 --tag services/m22 .
...

Notice, however, that each build has still to re-build the dependency modules; they are not shared across builds. Also, each build has to re-download all maven dependencies. This article at baeldung.com shows how to use a host directory as maven cache.

  • Related