You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多模块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"]

使用步骤

  1. 构建镜像:
    DOCKER_BUILDKIT=0 docker build --tag sb-multi-module-image --target multi-module .
    
  2. 启动web容器(默认):
    docker run -it --rm --name sb-web-container -p 8085:8080 sb-multi-module-image
    
  3. 启动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

使用步骤

  1. 构建镜像:
    DOCKER_BUILDKIT=0 docker build --tag sb-multi-module-image --target multi-module .
    
  2. 启动web容器:
    docker run -it --rm --name sb-web-container -p 8085:8080 sb-multi-module-image web
    
  3. 启动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"]

使用步骤

  1. 构建镜像:
    DOCKER_BUILDKIT=0 docker build --tag sb-multi-module-image --target multi-module .
    
  2. 启动web容器(默认):
    docker run -it --rm --name sb-web-container -p 8085:8080 sb-multi-module-image
    
  3. 启动worker容器:
    docker run -it --rm --name sb-worker-container -p 8086:8080 sb-multi-module-image /worker.jar
    

注意事项

  • 单镜像包含多JAR会增大镜像体积,但减少了镜像维护成本,适合模块关联度高的场景。
  • 两个模块的容器启动时要映射不同的宿主机端口,避免端口冲突。
  • 若后续新增模块,可统一将JAR放在指定目录,通过脚本或环境变量动态匹配,减少硬编码。

内容的提问来源于stack exchange,提问作者Sha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 07:36:29