多阶段构建通过分离编译与运行环境显著减小镜像体积:第一阶段用完整工具链编译并隔离中间产物,第二阶段仅显式复制必要文件至轻量基础镜像,避免隐式依赖,清理操作在构建阶段更有效。
多阶段构建能显著减小镜像体积,核心在于把“编译环境”和“运行环境”彻底拆开,让最终镜像只保留真正运行程序所需的极少数文件。
构建阶段只干活,不进最终镜像
第一阶段用完整工具链镜像(比如 golang:1.21 或 maven:3.8)做编译、下载依赖、打包。这个阶段体积大没关系,但它不会出现在最终镜像里。所有中间产物——源码、.git 目录、node_modules、target/、/var/cache/apk 等——都留在该阶段内部,不会自动带入下一阶段。
运行阶段只装最必要的东西
第二阶段换用轻量基础镜像(如 alpine:latest 或 distroless),它本身只有几 MB。你只能通过 COPY --from=builder 显式复制上一阶段中明确需要的文件,比如编译好的二进制、配置文件、证书等。其他一切都被天然隔离在外。
清理动作在构建阶段更有效
在构建阶段末尾加清理命令(例如 RUN go build -o app . && rm -rf /tmp/*),能减少该阶段产生的层大小;但更重要的是:即使没清理,只要不复制过去,就不会影响最终体积。而单阶段构建中,RUN rm 只是新增一层“标记删除”,原始数据仍在镜像中。
避免隐式依赖带入运行环境
比如 Go 项目开启 CGO_ENABLED=0 编译静态二进制,就不用在 Alpine 中再装 glibc 或 musl 兼容库;Java 项目用 spring-boot-maven-plugin 打成 fat jar 后,运行阶段只需 JRE,无需 Maven 或 JDK 全量环境。










