Docker多阶段构建核心是分离编译与运行:第一阶段用golang:1.21-alpine等含工具链镜像编译出二进制,第二阶段用alpine或distroless等极简镜像仅复制该文件,通过FROM...AS builder和COPY--from=builder实现精准产物传递。

直接用多阶段构建,核心就是把“编译”和“运行”拆开——构建阶段装一堆工具编译出二进制,运行阶段只复制这个文件,不带任何编译器、源码或中间产物。
明确划分两个阶段
第一阶段专注编译,选带完整工具链的镜像(比如 golang:1.21-alpine、maven:3.8-openjdk-17);第二阶段专注运行,选极简镜像(比如 alpine:latest、gcr.io/distroless/static)。关键在 FROM ... AS builder 和 COPY --from=builder 这两处语法。
- 给构建阶段起名:用
AS builder标记,后续才能引用 - 运行阶段不写
AS,它就是最终镜像的起点 -
COPY --from=builder只复制你需要的文件,比如/app/main或/target/app.jar
Go 应用典型写法
Go 静态编译后几乎不需要依赖,最适合多阶段。重点是关掉 cgo、加链接参数:
-
CGO_ENABLED=0确保生成纯静态二进制 -
GOOS=linux明确目标系统 -
-ldflags "-s -w"去掉调试符号和 DWARF 信息 - 运行阶段用
alpine就够了,连glibc都不用装
Java 应用注意点
Maven/Gradle 构建完通常生成一个 fat jar,多阶段的关键是别把整个构建目录搬过去:
- 构建阶段用
maven:3.8-openjdk-17,执行mvn package - 运行阶段别用 JDK 镜像,改用
openjdk:17-jre-slim或alpine-jre - 只复制
target/*.jar,别复制src/、pom.xml、target/classes - 如果用 Spring Boot,推荐
spring-boot-maven-plugin的repackage目标,确保是可执行 jar
额外瘦身技巧
多阶段只是第一步,配合这些操作效果更明显:
- 基础镜像选
alpine(约 5MB)或distroless(约 2–5MB),避开ubuntu(>1GB) - 运行阶段里用
RUN apk --no-cache add ca-certificates替代apt-get,安装完不残留缓存 - 用
.dockerignore排除node_modules、.git、tests等本地无关文件 - 合并 RUN 指令,比如把
apk add和mkdir写在同一行,减少镜像层


















