分享一个Dockerfile的三阶段构建

不清楚这种用法业界用得多不对,感觉蛮好玩的

完整文件

FROM maven:3-ibm-semeru-21-jammy as mvn_build
WORKDIR app
COPY . .
# RUN mvn dependency:go-offline
RUN mvn clean package \
    -U -DskipTests \
    -Dmaven.repo.local=/root/.m2/repository \
    -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \
    -T$(grep -c ^processor /proc/cpuinfo)

################################

FROM eclipse-temurin:21-jre as jar_build
WORKDIR app
COPY --from=mvn_build /app/target/super.jar super.jar
RUN java -Djarmode=layertools -jar super.jar extract

################################

FROM ibm-semeru-runtimes:open-21-jre
WORKDIR app
COPY --from=jar_build app/dependencies/ ./
COPY --from=jar_build app/spring-boot-loader/ ./
COPY --from=jar_build app/snapshot-dependencies/ ./
COPY --from=jar_build app/application/ ./
ENV JVM_OPTS="-Xmx256m -Xms256m" \
    TZ=Asia/Shanghai
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java ${JVM_OPTS} org.springframework.boot.loader.launch.JarLauncher ${0} ${@}"]

阶段分解:

阶段 1:打包

FROM maven:3-ibm-semeru-21-jammy as mvn_build
WORKDIR app
COPY . .
# RUN mvn dependency:go-offline
RUN mvn clean package \
    -U -DskipTests \
    -Dmaven.repo.local=/root/.m2/repository \
    -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn \
    -T$(grep -c ^processor /proc/cpuinfo)
  • WORKDIR app: 设置工作目录为 /app
  • COPY . .: 将整个项目复制到容器中。
  • RUN mvn dependency:go-offline: 缓存依赖,以加快后续构建速度(按需使用)。
  • RUN mvn clean package: 运行 Maven 以清理和打包应用程序。
    • -U: 强制更新快照。
    • -DskipTests: 跳过测试。
    • -Dmaven.repo.local=/root/.m2/repository: 指定本地 Maven 仓库。
    • -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn: 设置 Maven 传输事件的日志级别。
    • -T$(grep -c ^processor /proc/cpuinfo): 使用所有可用的 CPU 核心进行构建。

阶段 2:包优化

FROM eclipse-temurin:21-jre as jar_build
WORKDIR app
COPY --from=mvn_build /app/target/super.jar super.jar
RUN java -Djarmode=layertools -jar super.jar extract
  • WORKDIR app: 设置工作目录为 /app
  • COPY --from=mvn_build /app/target/super.jar super.jar: 从 mvn_build 阶段复制构建好的 JAR 文件。
  • RUN java -Djarmode=layertools -jar super.jar extract: 使用 layertools 模式提取 JAR 文件的层,属于Spring Boot的一个特性,用于优化 Docker 镜像的构建。

阶段 3:运行时环境

FROM ibm-semeru-runtimes:open-21-jre
WORKDIR app
COPY --from=jar_build app/dependencies/ ./
COPY --from=jar_build app/spring-boot-loader/ ./
COPY --from=jar_build app/snapshot-dependencies/ ./
COPY --from=jar_build app/application/ ./
ENV JVM_OPTS="-Xmx256m -Xms256m" \
    TZ=Asia/Shanghai
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "java ${JVM_OPTS} org.springframework.boot.loader.launch.JarLauncher ${0} ${@}"]
  • WORKDIR app: 设置工作目录为 /app
  • COPY --from=jar_build app/dependencies/ ./: 复制依赖层。
  • COPY --from=jar_build app/spring-boot-loader/ ./: 复制 Spring Boot 加载器层。
  • COPY --from=jar_build app/snapshot-dependencies/ ./: 复制快照依赖层。
  • COPY --from=jar_build app/application/ ./: 复制应用程序层。
  • ENV JVM_OPTS=“-Xmx256m -Xms256m” TZ=Asia/Shanghai: 设置 JVM 选项和时区环境变量。
  • EXPOSE 8080: 暴露 8080 端口。
  • ENTRYPOINT ["sh", "-c", "java ${JVM_OPTS} org.springframework.boot.loader.launch.JarLauncher ${0} ${@}"]: 设置入口点以启动应用程序。

构建命令

docker build -v /xxx/.m2:/root/.m2 -t super .

6 个赞

一般都是这样的,不过也存在本地编译后移到镜像内直接执行的情况,就是阶段1在主机上编译好。
其实还是看用没用到CI,流程是怎么写的。
你发的这个其实很标准了,后面就注意容器安全性问题还有镜像压缩就ok

1 个赞

取决于是不是编译型的编程语言 go啊 java啊 可以
php py js大可不必

1 个赞

mark!!!

我平时写 golang 的项目,一般也是分 2 阶段构建

有时候感觉这种阶段构建项目复杂了真的还挺复杂的。

感谢大佬分享!