多阶段构建通过多个FROM指令分离构建与运行环境,仅保留最小运行文件,显著减小镜像体积、提升安全性和部署效率;其核心是构建器阶段编译、运行阶段仅复制二进制,阶段间隔离需显式COPY --from提取。

多阶段构建通过在Dockerfile中使用多个FROM指令,把构建过程和运行环境分离,最终只保留运行所需的最小文件,显著减小镜像体积、提升安全性与部署效率。
理解多阶段构建的核心逻辑
传统单阶段构建会把编译工具链、依赖源码、中间产物全部打包进最终镜像,而多阶段构建利用“构建器阶段”(如builder)完成编译,再在“运行阶段”(如alpine或scratch)中仅复制二进制文件或必要资源。两个阶段彼此隔离,前一阶段的文件不会自动带入后一阶段,必须显式用COPY --from=xxx提取。
典型Go应用多阶段构建示例
以Go项目为例,无需安装Go环境到生产镜像中:
- 第一阶段用
golang:1.22-alpine作为构建器:WORKDIR /app,COPY . .,go build -o myapp . - 第二阶段用
alpine:latest(或更小的scratch):COPY --from=0 /app/myapp /usr/local/bin/myapp - 设置非root用户:
RUN addgroup -g 1001 -f appgroup && adduser -S appuser -u 1001,再USER appuser - 指定启动命令:
ENTRYPOINT ["/usr/local/bin/myapp"]
精简技巧与避坑要点
不是所有多阶段都能自动变小,需主动干预:
- 避免在运行阶段
COPY --from=0 /全量复制,只取/app/myapp或/usr/src/app/dist等明确路径 - 启用Go静态编译:
go build -a -ldflags '-extldflags "-static"' -o myapp .,这样可安全切换到scratch基础镜像 - 构建时加
--no-cache防止缓存污染;用--target builder调试中间阶段 - Node.js项目可用
node:18-alpine构建 +node:18-alpine-slim运行,npm ci --only=production跳过devDependencies
验证与对比方法
构建前后用命令直观对比效果:
-
docker build -t myapp:full .(单阶段)→ 查看docker images myapp:full大小 -
docker build -t myapp:multi --target runtime .(指定运行阶段)→ 再查镜像大小 -
docker history myapp:multi确认层数是否减少、每层内容是否合理 - 运行容器后执行
docker exec -it,确认只有目标二进制,无ls -l /usr/local/bin/ go、npm等无关工具










