多阶段构建本身不直接实现开发与生产镜像隔离,而是通过明确划分dev、build、prod等阶段并配合--target控制输出,使二者在基础镜像、内容、权限及标签上完全独立,从而自然达成严格隔离。
多阶段构建本身不直接实现“开发与生产镜像的隔离”,它解决的是构建环境与运行环境的分离。但正因这种分离能力,配合合理设计,可以自然支撑开发镜像和生产镜像的职责分化与完全隔离——关键不在“用了几个阶段”,而在每个阶段的目标是否明确、产物是否严格受控。
用不同阶段定义不同用途的镜像
一个 Dockerfile 可以包含三个及以上阶段,不只是 build + production:
- dev 阶段:基于 node:20 或 golang:1.22-alpine,装好调试工具(delve、nodemon)、源码、依赖,并暴露端口、挂载热重载卷——专供本地或 CI 调试用
-
build 阶段(可命名如
AS builder):干净环境,只拉依赖、编译、运行测试,生成二进制或 dist 包,不保留源码和 dev 工具 -
prod 阶段(如
FROM alpine:3.20或scratch):仅 COPY 构建产物,设非 root 用户,删掉所有非运行必需路径(如 /tmp、/var/cache)
这样,开发镜像(--target dev)和生产镜像(默认构建或 --target prod)从基础镜像、安装内容、启动方式到安全配置全部不同,天然隔离。
通过 --target 控制输出,避免混用
构建命令决定最终产出哪个镜像,不会互相污染:
-
docker build --target dev -t myapp:dev .→ 得到含 nodemon 的开发镜像 -
docker build --target prod -t myapp:latest .→ 得到 15MB 的纯运行镜像 - CI 流水线只跑
--target prod,开发人员本地只跑--target dev
两个镜像在镜像层、历史记录、文件系统上完全独立,没有共享中间层,也没有复用风险。
用 ARG 和条件指令进一步区分行为
在单个阶段内也可做轻量分支,比如在 build 阶段根据参数决定是否运行单元测试:
- 定义
ARG RUN_TESTS=true,并在 build 阶段用RUN ${RUN_TESTS:+npm test} - 开发构建时传
--build-arg RUN_TESTS=false加速,生产构建强制为 true - 所有 ARG 变量不会进入最终镜像,不影响 prod 镜像纯净性
配套机制加固隔离效果
单靠 Dockerfile 不够,还需流程与规范配合:
- 镜像标签强约定:
:dev、:staging、:v1.2.0,禁止将 dev 镜像推送到生产仓库 - CI 系统限制:只有合并到 main 分支才允许触发
--target prod构建 - Kubernetes 或 Docker Swarm 部署时,明确指定
image: myapp:latest,绝不使用 latest 指向 dev 镜像










