多阶段构建通过分离构建与运行阶段,仅复制必要产物到极简基础镜像(如alpine或scratch),精准剥离工具链与源码,使镜像从几百mb压至十几mb。

多阶段构建不是“加几个FROM就行”,关键在于精准剥离构建依赖,只保留运行必需的文件。用对阶段、选对基础镜像、复制对内容,几百MB甚至几GB的镜像就能压到十几MB。
明确划分构建与运行两个核心阶段
第一阶段专注编译或安装——用带完整工具链的镜像(如 node:20、golang:1.21、maven:3.8),完成依赖安装、代码编译、打包等任务;第二阶段专注运行——换用极简镜像(如 alpine:latest 或 scrach),不装任何开发工具,只接收前一阶段产出的可执行文件或静态资源。
- 每个阶段用 AS 命名(如
AS builder、AS runner),方便后续引用 - 避免在最终阶段重复安装 npm、go、maven 等工具,它们只属于构建阶段
- 不要在运行阶段
COPY .整个源码目录,只复制dist/、build/或二进制文件
优先选用轻量基础镜像作为运行环境
最终镜像体积很大程度取决于基础镜像本身。Ubuntu 镜像约 70MB,Alpine 仅约 5MB,而 scratch 是空镜像(0MB),适合纯静态二进制文件。
- Go 应用推荐
FROM scratch,前提是开启CGO_ENABLED=0编译静态链接版 - Node.js 应用推荐
node:20-alpine,比node:20(Debian系)小 60% 以上 - Java 应用可用
eclipse-jre:17-jre-alpine或azul/zulu-openjdk:17-jre-alpine替代 full JDK 镜像
按需复制,杜绝冗余文件混入最终镜像
用 COPY --from=xxx 精确指定来源路径,避免把 node_modules 全量复制过去,也别把 src/、test/、package-lock.json 带进运行镜像。
- Node.js 场景:只从
deps阶段复制node_modules,从builder阶段复制dist/和package*.json - Go 场景:只复制编译好的二进制,不复制
.go源码、go.mod或构建缓存 - Java 场景:只复制
target/*.jar,不复制src/、target/maven-archiver/等中间产物
利用阶段别名做调试和分步验证
多阶段构建支持选择性构建某一个阶段,这对排查问题非常实用。
- 只构建依赖安装阶段:
docker build --target deps -t myapp:deps . - 只构建打包阶段:
docker build --target builder -t myapp:build . - 跳过前面阶段直接验证运行镜像:
docker build --target runner -t myapp:prod . - 配合
docker run -it myapp:build sh进入构建镜像检查产物是否齐全











