Docker多阶段构建的核心是分离编译与运行环境,通过多个FROM指令精简镜像、提升安全、优化CI/CD;例如Java项目先用maven镜像构建JAR,再以openjdk-slim运行,仅保留必需文件和非root用户权限。

Docker 多阶段构建在容器化改造中,核心是把“怎么编”和“怎么跑”彻底分开。它不是炫技用的高级功能,而是解决实际问题的刚需工具——比如镜像太大、启动太慢、安全扫描一堆高危漏洞。
分离编译环境与运行环境,只留运行必需的东西
传统方式常把 JDK、Maven、npm、gcc 全塞进一个镜像里,结果 1.2GB 镜像里真正运行程序的可能就几 MB。多阶段构建用两个(或多个) FROM 指令划清边界:
- 第一阶段用完整工具链编译代码、安装依赖、生成产物(如 JAR、二进制、dist 文件)
- 第二阶段换轻量基础镜像(如
alpine、debian:slim、distroless),只 COPY 上一阶段的成品
例如 Java 应用:
FROM maven:3.8.6-openjdk-17 AS builder WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline -B COPY src ./src RUN mvn package -DskipTests FROM openjdk:17-jre-slim WORKDIR /app COPY --from=builder /app/target/app.jar . EXPOSE 8080 CMD ["java", "-jar", "app.jar"]
让不同语言项目都受益,不止是 Go 或 Java
- Node.js:第一阶段用
node:18-alpine装依赖 + 构建前端资源,第二阶段用nginx:alpine托管静态文件 - Python:第一阶段用
python:3.11-slim安装带编译的包(如psycopg2-binary),第二阶段用python:3.11-slim-bookworm只复制 site-packages 和脚本 - C/C++:第一阶段用
gcc:12编译,第二阶段用scratch或alpine运行静态链接的二进制
控制权限、减少攻击面,不只是减体积
光瘦身不够,还得防爆破:
- 构建阶段可 root 安装一切,运行阶段必须切非 root 用户(
useradd+USER) - 不复制
.git、node_modules、__pycache__、临时构建目录(如target/下的中间文件) - 健康检查用内置能力(如 Python 的
urllib、Go 的http.Get),不额外装curl或wget
配合 CI/CD 流水线,一次构建,多处复用
- 同一个 Dockerfile 可产出测试镜像(含调试工具)、预发镜像(带配置注入)、生产镜像(最小+非 root)
- 利用
--target参数按需构建某阶段:docker build --target builder .快速验证编译逻辑 - 结合 BuildKit 的
--mount=type=cache加速依赖下载,避免每次重拉 Maven repo 或 pip cache
本质上,多阶段构建不是“要不要用”,而是“怎么用得更稳”。它把原本散落在 CI 脚本、部署文档、运维 checklist 里的最佳实践,收束到一份可读、可测、可版本化的 Dockerfile 里。


















