多阶段构建是什么
在同一个 Dockerfile 中区分构建阶段与运行阶段:编译依赖留在构建层,运行镜像只带产物,体积与攻击面同步缩小。语法:FROM ... AS build 声明构建阶段;后续 FROM 基于运行基础镜像,用 COPY --from=build 拷贝产物。收益是运行镜像不含编译器与源码(除需要外)。扩展用法:多阶段还可承载测试阶段与产物提取,例如从构建阶段导出文件而不让其进入最终镜像。
基本信息
| 语法 | FROM ... AS build;后续 FROM 配 COPY --from=build 拷贝产物 |
|---|---|
| 收益 | 运行镜像不含编译器与源码(除需要外) |
| 扩展 | 多阶段还可用于测试阶段与产物提取 |
| 缓存技巧 | 先拷贝依赖清单再拷源码,依赖层稳定复用 |
| 基础镜像 | 运行阶段选最小镜像(精简发行版或静态镜像) |
典型使用场景
- 编译型语言:Go、Rust、Java 等先构建再拷贝产物的标准做法。
- 前端构建:node 阶段构建静态文件,运行阶段用 nginx 托管产物。
- 体积优化:运行镜像从完整 SDK 镜像换成运行时镜像,体积大幅缩小。
- 攻击面控制:运行镜像不含编译器与包管理器,漏洞扫描噪音同步减少。
- 测试阶段:中间阶段跑测试,失败即整个构建失败。
- 产物提取:用目标阶段仅导出构建产物,供其他流程使用。
Go 示例
Go 示例
FROM golang:1.22 AS build
WORKDIR /src
COPY go.mod go.sum ./ # 先拷依赖清单
RUN go mod download # 依赖独立成层,稳定命中缓存
COPY . .
RUN CGO_ENABLED=0 go build -o /out/app ./cmd/app
FROM gcr.io/distroless/static-debian12
COPY --from=build /out/app /app
ENTRYPOINT ["/app"]依赖清单先行、源码后置:依赖层稳定命中缓存,改代码不必重下依赖。
构建阶段与运行阶段基础镜像的 libc 不一致时,二进制在运行阶段直接报错(如 glibc 与 musl 混用)。
多阶段主要减少镜像体积与泄露面:构建时间优化靠层缓存与并行,不是靠阶段数量本身。