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?
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.