Home > Enterprise >  Single Docker Image Multiple Container For Multi Module Java Project
Single Docker Image Multiple Container For Multi Module Java Project

Time:08-29

I have created a project like https://github.com/senolatac/demo-multi-module-docker and I have implemented some docker multi-stage https://docs.docker.com/language/java/run-tests/ examples.

Here is my Dockerfile:

FROM --platform=linux/x86_64 gradle:7.5.1-jdk17-alpine AS base
COPY --chown=gradle:gradle . /app
WORKDIR /app

FROM base as test
CMD ["./gradlew", "test"]

FROM base as build
RUN ./gradlew build -x test

# create-image -> DOCKER_BUILDKIT=0 docker build --tag sb-web-image --target web .
# run -> docker run -it --rm --name sb-web-container -p 8085:8080 sb-web-image
FROM --platform=linux/x86_64 openjdk:17-alpine as web
COPY --from=build /app/web/build/libs/*.jar /web.jar
CMD ["java", "-Dspring-boot.run.profiles=default", "-jar", "/web.jar"]

# create-image -> DOCKER_BUILDKIT=0 docker build --tag sb-worker-image --target worker .
# run -> docker run -it --rm --name sb-worker-container -p 8086:8080 sb-worker-image
FROM --platform=linux/x86_64 openjdk:17-alpine as worker
COPY --from=build /app/worker/build/libs/*.jar /worker.jar
CMD ["java", "-Dspring-boot.run.profiles=default", "-jar", "/worker.jar"]

# create-image -> DOCKER_BUILDKIT=0 docker build --tag sb-web-image --build-arg JAR_FILE=web/build/libs/\*.jar --target generic .
# run -> docker run -it --rm --name sb-web-container -p 8086:8080 sb-web-image
FROM --platform=linux/x86_64 openjdk:17-alpine as generic
ARG JAR_FILE
COPY --from=build /app/${JAR_FILE} /app.jar
CMD ["java", "-Dspring-boot.run.profiles=default", "-jar", "/app.jar"]

My project has two different modules. To run these modules on Docker, firstly I should create two different images then run them as two different docker container. But my purpose is so simple: Create a single image and run containers from that image. Do you have suggestion about it?

CodePudding user response:

You can straightforwardly override the CMD when you run the application, so you just need to COPY all of the jar files into the single image.

FROM --platform=linux/x86_64 gradle:7.5.1-jdk17-alpine AS build
COPY --chown=gradle:gradle . /app
WORKDIR /app
RUN ./gradlew build -x test

FROM --platform=linux/x86_64 openjdk:17-alpine
WORKDIR /app
COPY --from=build /app/web/build/libs/*.jar ./web.jar
COPY --from=build /app/worker/build/libs/*.jar ./worker.jar
ENV SPRINGBOOT_RUN_PROFILES=default
EXPOSE 8080
CMD ["java", "-jar", "./web.jar"]
docker build -t sb-image .
docker run -d --name sb-web -p 8085:8080 sb-image
docker run -d --name sb-worker -p 8086:8080 sb-image \
  java -jar ./worker.jar

So, note that there is only one final stage, but it COPY --from=build both jar files into it. I pick one of them to be the default CMD, and when I run the other, I provide an additional command after the docker run image-name. (Compose command: and Kubernetes args: can do the same thing.)

This looks like a Spring Boot application. I've set the profile property as an environment variable rather than a command-line option, which shortens the command line. If your applications share a code base, you can also get a smaller image by unpacking the fat jars, though this requires an additional build stage.

  • Related