题目
Dockerfile 多阶段构建
答案
多阶段构建(Multi-stage Build)是 Docker 中的一种高级构建技术,通过将一个 Dockerfile 分成**多个独立的构建阶段**,最终仅保留需要的文件和运行时环境,从而**显著减小镜像体积**并提升安全性。它的核心思想是 **“构建环境”和“运行环境”分离**,避免将编译工具、中间文件等无关内容打包到最终镜像中。 在传统单阶段构建中,镜像会包含所有构建工具和临时文件(如 Maven、Gradle、编译生成的中间文件等),导致镜像臃肿且存在安全隐患。例如单阶段构建的 Spring Boot 镜像包含 JDK、Maven、源码、依赖包等,而多阶段构建的 Spring Boot 镜像仅包含 JRE 和编译后的 JAR 包,体积大大减少。 多阶段构建的工作原理: 1. 定义多个阶段:每个阶段以 `FROM` 指令开头,并为阶段命名(如 `FROM ... AS builder`)。 2. 分阶段操作: - 第一阶段(构建阶段):安装构建工具(如 Maven、GCC),编译代码,生成可执行文件。 - 后续阶段(运行阶段):从之前的阶段复制**仅需的运行文件**(如 JAR 包、二进制文件),使用轻量级基础镜像(如 Alpine)。 3. 最终镜像:仅保留最后一个阶段的内容,之前阶段的中间产物会被自动丢弃。 以下是 Spring Boot 应用的多阶段 Dockerfile 示例: 单阶段 Dockerfile: ```yaml # ===== 单阶段构建(包含构建和运行环境)===== FROM maven:3.8.6-openjdk-17 # 直接使用包含 JDK 和 Maven 的镜像 # 设置工作目录 WORKDIR /app # 复制源码和 POM 文件 COPY pom.xml . COPY src ./src # 下载依赖并构建应用(生成 JAR 包) RUN mvn dependency:go-offline -B && \ mvn package -DskipTests # 暴露端口 EXPOSE 8080 # 运行 JAR(镜像中包含完整的 JDK 和 Maven) ENTRYPOINT ["java", "-jar", "/app/target/*.jar"] ``` 多阶段 Dockerfile: ```yaml # ===== 第一阶段:构建阶段(命名为 builder)===== FROM maven:3.8.6-openjdk-17 AS builder # 使用完整的 JDK 和 Maven # 设置工作目录 WORKDIR /app # 复制源码和 POM 文件 COPY pom.xml . COPY src ./src # 下载依赖并构建应用(生成 JAR 包) RUN mvn dependency:go-offline -B RUN mvn package -DskipTests # ===== 第二阶段:运行阶段 ===== # 使用轻量级镜像(仅含 JRE) FROM openjdk:17-jdk-alpine # 设置工作目录 WORKDIR /app # 重要!从构建阶段复制 JAR 包 COPY --from=builder /app/target/*.jar app.jar # 暴露端口 EXPOSE 8080 # 运行 JAR ENTRYPOINT ["java", "-jar", "app.jar"] ``` 关键步骤说明: 1. **构建阶段**: - 使用 `maven:3.8.6-openjdk-17` 镜像,包含完整的 JDK 和 Maven。 - 通过 `mvn package` 编译代码,生成 `target/app.jar`。 2. **运行阶段**: - 使用轻量级 `openjdk:17-jdk-alpine` 镜像(体积更小)。 - 通过 `COPY --from=builder` 从构建阶段复制编译好的 `app.jar`。 - 最终镜像**不包含 Maven、源码、临时文件**,仅保留运行所需的 JRE 和 JAR。