多阶段构建通过分离构建与运行环境实现镜像瘦身:构建阶段用含sdk的镜像(如golang:1.21)编译代码,运行阶段用轻量镜像(如alpine:latest)仅复制二进制文件,借助copy --from=builder精准传递产物,自动丢弃编译工具、源码等冗余内容。
用多阶段构建分离编译与运行环境,核心是让不同阶段各司其职:前一阶段装工具、编译代码,后一阶段只放可执行文件和最小运行依赖。
明确划分两个阶段:构建阶段 + 运行阶段
每个阶段以 FROM 开头,可指定不同基础镜像。构建阶段用带 SDK 的镜像(如 golang:1.21、maven:3.9-openjdk-17),运行阶段选轻量镜像(如 alpine:latest、debian:slim 或 scratch)。
- 构建阶段不暴露在最终镜像中,所有中间产物(源码、依赖包、编译器)自动丢弃
- 运行阶段不能执行编译命令,也不应包含任何开发工具
- 阶段之间用 --from=阶段名 复制文件,例如
COPY --from=builder /app/app /usr/local/bin/
Go 应用典型写法(静态编译 + Alpine 运行)
Go 编译出静态二进制,天然适合多阶段瘦身:
- 第一阶段用
golang:1.21,设别名为builder,完成go build -a -ldflags '-s -w' - 关键要加
CGO_ENABLED=0,确保生成不依赖系统 libc 的静态文件 - 第二阶段用
alpine:latest,只COPY --from=builder二进制,直接CMD ["./app"]
Java 应用常见结构(Maven 构建 + JRE 运行)
Java 不像 Go 那样能一键静态链接,但依然能大幅精简:
- 构建阶段用
maven:3.9-openjdk-17,运行mvn clean package,产出target/*.jar - 运行阶段推荐
eclipse-jre:17-jre-slim或amazoncorretto:17-jre-alpine - 复制 jar 包后,用
java -jar app.jar启动,不装 Maven、不放src和pom.xml
注意几个易错细节
多阶段不是写完就生效,有些地方不留意会白忙活:
- 阶段名区分大小写,
--from=Builder和--from=builder是两回事 - 路径必须准确,
COPY --from=builder /work/app /中的/work/app要和构建阶段WORKDIR或RUN输出路径一致 - 若需多个文件,建议统一放在一个目录下再整体复制,避免漏项
- 运行阶段若用
scratch,必须确保二进制是完全静态链接的(Go 可行,Java 不行)











