多模块Java项目:单Docker镜像运行多容器的实现方案咨询
问题描述
我创建了一个多模块Java项目,用Gradle构建,已实现Docker多阶段构建,当前的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"]
项目包含web和worker两个模块,目前需要构建两个独立镜像才能分别运行对应容器,我希望实现单Docker镜像即可运行这两个模块的容器,请问有哪些可行的实现方案?
实现方案
方案一:打包多JAR,通过环境变量指定运行模块
把两个模块的JAR都复制到同一个镜像里,用环境变量控制启动哪个模块,操作简单直观。
修改后的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 FROM --platform=linux/x86_64 openjdk:17-alpine as multi-module # 复制两个模块的JAR到镜像 COPY --from=build /app/web/build/libs/*.jar /web.jar COPY --from=build /app/worker/build/libs/*.jar /worker.jar # 默认启动web模块 ENV MODULE=web # 根据环境变量启动对应JAR CMD ["sh", "-c", "java -Dspring-boot.run.profiles=default -jar /${MODULE}.jar"]
使用步骤
- 构建镜像:
DOCKER_BUILDKIT=0 docker build --tag sb-multi-module-image --target multi-module . - 启动web容器(默认):
docker run -it --rm --name sb-web-container -p 8085:8080 sb-multi-module-image - 启动worker容器:
docker run -it --rm --name sb-worker-container -p 8086:8080 -e MODULE=worker sb-multi-module-image
方案二:添加启动脚本,通过参数选择模块
在镜像中加入自定义启动脚本,根据启动时传入的参数选择运行的模块,适合后续扩展更多模块的场景。
修改后的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 FROM --platform=linux/x86_64 openjdk:17-alpine as multi-module COPY --from=build /app/web/build/libs/*.jar /web.jar COPY --from=build /app/worker/build/libs/*.jar /worker.jar # 复制启动脚本到镜像 COPY start.sh /start.sh RUN chmod +x /start.sh # 用脚本作为启动命令 CMD ["/start.sh"]
编写start.sh脚本(放在项目根目录)
#!/bin/sh if [ "$1" = "web" ]; then java -Dspring-boot.run.profiles=default -jar /web.jar elif [ "$1" = "worker" ]; then java -Dspring-boot.run.profiles=default -jar /worker.jar else echo "请指定要启动的模块:web 或 worker" exit 1 fi
使用步骤
- 构建镜像:
DOCKER_BUILDKIT=0 docker build --tag sb-multi-module-image --target multi-module . - 启动web容器:
docker run -it --rm --name sb-web-container -p 8085:8080 sb-multi-module-image web - 启动worker容器:
docker run -it --rm --name sb-worker-container -p 8086:8080 sb-multi-module-image worker
方案三:用ENTRYPOINT+CMD组合实现灵活启动
通过ENTRYPOINT固定启动命令的基础部分,用CMD传递默认的JAR路径,启动时可直接覆盖CMD指定其他模块。
修改后的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 FROM --platform=linux/x86_64 openjdk:17-alpine as multi-module COPY --from=build /app/web/build/libs/*.jar /web.jar COPY --from=build /app/worker/build/libs/*.jar /worker.jar # 固定启动命令的前缀部分 ENTRYPOINT ["java", "-Dspring-boot.run.profiles=default", "-jar"] # 默认启动web模块的JAR CMD ["/web.jar"]
使用步骤
- 构建镜像:
DOCKER_BUILDKIT=0 docker build --tag sb-multi-module-image --target multi-module . - 启动web容器(默认):
docker run -it --rm --name sb-web-container -p 8085:8080 sb-multi-module-image - 启动worker容器:
docker run -it --rm --name sb-worker-container -p 8086:8080 sb-multi-module-image /worker.jar
注意事项
- 单镜像包含多JAR会增大镜像体积,但减少了镜像维护成本,适合模块关联度高的场景。
- 两个模块的容器启动时要映射不同的宿主机端口,避免端口冲突。
- 若后续新增模块,可统一将JAR放在指定目录,通过脚本或环境变量动态匹配,减少硬编码。
内容的提问来源于stack exchange,提问作者Sha
相关产品推荐
相关产品推荐

