多阶段构建的核心是分离构建与运行环境:构建阶段使用含完整工具链的镜像(如golang:1.22-alpine),运行阶段仅复制必要产物至轻量镜像(如alpine:latest),通过copy --from=builder精准传递文件,避免隐式污染和层冗余。
多阶段构建的核心是用不同容器环境分工协作:构建环境装全依赖、编译代码;运行环境只留最小必要文件。优雅高效的关键不在“写得多”,而在“删得准”——精准复制产物、避免隐式污染、减少镜像层冗余。
明确阶段职责,避免环境混用
每个 FROM 都应有清晰语义,不复用构建镜像做运行时,也不在运行阶段安装编译工具。
- 构建阶段用
golang:1.22-alpine或node:20-slim等带完整工具链的镜像 - 运行阶段优先选
alpine:latest、debian:slim或语言官方-alpine/-slim变体 - 避免在运行阶段写
RUN apt-get update && apt-get install -y ...—— 这会残留缓存层和无用包
精准复制产物,跳过中间文件
用 COPY --from=builder 显式指定路径,不依赖工作目录或隐式结构。
- Go 示例:
COPY --from=builder /app/myapp /usr/local/bin/myapp(直接拷二进制) - Node 示例:
COPY --from=builder /app/dist/ ./dist/,再COPY --from=builder /app/package.json .,而非整个/app - 避免
COPY --from=builder /app/ .—— 容易带入node_modules、src/、build/等非运行所需内容
利用构建参数与命名阶段提升可维护性
用 ARG 控制版本,用 AS 命名阶段,让脚本更易读、易调试、易复用。
- 定义构建参数:
ARG NODE_VERSION=20.11.1,然后FROM node:${NODE_VERSION}-slim AS builder - 命名阶段如
AS frontend-builder、AS backend-builder,便于多服务复用同一 Dockerfile - 调试时可单独构建某阶段:
docker build --target frontend-builder -t my-fe .
精简运行环境,主动清理无用层
运行阶段不是“越小越好”,而是“刚好够用”。主动删除临时文件、文档、缓存,但别误删依赖。
- Alpine 中删 docs:
RUN apk del .build-deps && rm -rf /var/cache/apk/* - Debian/Ubuntu 中删 man 和 doc:
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man - 避免
RUN rm -rf /tmp/*—— 某些程序依赖/tmp目录存在,只需清空内容而非目录本身
不复杂但容易忽略:多阶段不是炫技,是克制。少一层 RUN,少一个 COPY,少一个 ARG 默认值,往往就更可靠。










