多阶段构建是持续部署中提升交付稳定性、速度与安全性的核心设计手段,通过拆分builder和runtime阶段实现镜像精简、环境隔离、构建复用与不可变部署。

多阶段构建在持续部署中不是“额外加功能”,而是让整个交付链路更稳、更快、更安全的核心设计手段。它不改变 CI/CD 流水线结构,而是深度嵌入 Docker 构建环节,从源头控制镜像质量。
用多阶段构建替代单阶段打包
传统做法常把编译、测试、打包全塞进一个镜像里,结果镜像又大又慢,还带一堆 dev 工具——CI 构建一次耗时长,部署时拉取慢,运行时风险高。多阶段构建直接拆开这件事:
- 第一阶段(builder):用完整工具链编译源码、跑单元测试、生成可执行文件或静态资源包
- 第二阶段(runtime):只用 Alpine、distroless 或 slim 镜像,复制上一阶段产物,不带任何编译器、源码、dev 依赖
- 最终产出的镜像体积通常压到 10–50MB,启动快、传输快、攻击面小
和 GitLab CI 的 stage 精准对齐
GitLab CI 的 stages(如 build/test/deploy)和 Docker 的多阶段(builder/runtime)不是平行关系,而是嵌套协作:
-
build阶段里跑docker build --target builder,快速验证编译流程是否通 -
test阶段可基于 builder 镜像运行集成测试,不污染 runtime 环境 -
deploy阶段才构建最终 runtime 镜像,并推送到 registry - 这样既支持分步调试,又避免为测试单独维护一套构建逻辑
按环境输出不同镜像变体
一个 Dockerfile 可定义多个目标阶段,配合 CI 变量灵活选择:
-
FROM golang:1.21 AS builder-dev→ 带调试工具,用于开发分支 -
FROM golang:1.21 AS builder-prod→ 关闭调试符号,启用 -ldflags,用于 main 分支 -
FROM alpine:latest AS runtime→ 所有环境共用,只接收编译产物 - CI 中用
--target $CI_ENVIRONMENT_TYPE控制构建哪一段,无需维护多份 Dockerfile
提升部署可靠性与可观测性
多阶段构建让部署产物真正“不可变”:
- runtime 镜像不含构建时间戳、本地路径、临时文件,SHA256 指纹稳定可追溯
- 结合 CI 的 artifact 缓存机制,相同代码提交会复用 builder 阶段缓存,加快构建速度
- 镜像扫描工具(如 Trivy)只需检查 runtime 阶段,大幅缩短安全检测耗时
- 运维人员一眼能看出镜像里只有二进制+ca-certificates,没有 npm/yarn/maven,心里踏实











