首页/开发/CI/CD 与发布速查/Docker 多阶段构建
构建与制品管理58 条

Docker 多阶段构建

在同一个 Dockerfile 中区分构建阶段与运行阶段:编译依赖留在构建层,运行镜像只带产物,体积与攻击面同步缩小。

CI/CD 与发布速查开发更新于 2026-10-13

多阶段构建是什么

在同一个 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 混用)。
多阶段主要减少镜像体积与泄露面:构建时间优化靠层缓存与并行,不是靠阶段数量本身。

易错点

  • 运行阶段误拷贝整个工作目录:把源码与缓存带进镜像,应选择精确路径。
  • 构建与运行阶段基础镜像 libc 不一致:二进制在运行阶段直接报错。
  • 忽略静态与动态链接选项:依赖与目标镜像不匹配,容器内运行即崩溃。
  • 依赖清单与源码拷贝顺序颠倒:每次改代码都重下依赖,构建时间无谓拉长。
  • 运行阶段仍用完整 SDK 镜像:体积与攻击面没有优化,多阶段只做了一半。

数据来源与参考

  • Docker Docs《Multi-stage builds》
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌