核心目标是分离构建与运行环境,仅将必要产物复制到精简镜像中,从而减小体积、提升安全性、缩短拉取时间并增强缓存复用;第一阶段用完整开发镜像编译,第二阶段用alpine等轻量镜像仅运行产物。

构建多阶段 Docker 镜像的核心目标是分离构建环境与运行环境,只把真正需要的文件带入最终镜像——这样能显著减小体积、缩短拉取时间、缩小攻击面,并提升缓存复用率。
明确划分构建与运行两个阶段
第一阶段(构建阶段)使用功能完整的开发镜像(如 node:18-slim 或 golang:1.20-alpine),安装全部依赖、复制源码、执行编译或打包。第二阶段(运行阶段)选用精简基础镜像(如 node:18-alpine 或 alpine:3.18),仅复制上一阶段生成的产物(如 dist/、node_modules/、可执行二进制文件)和必要配置。
- 避免在最终镜像中保留
git、gcc、make等构建工具 - 不复制
src/、.git/、test/等非运行时所需内容(除非调试必需) - 用
COPY --from=builder精确控制哪些路径被带入运行镜像
优化构建流程以提升缓存命中率
Docker 按指令顺序逐层构建,一旦某层失效,后续所有层都会重建。因此要让变化少的操作尽量靠前。
- 先
COPY package.json yarn.lock ./,再RUN yarn install—— 依赖不变时,这层缓存长期有效 - 再
COPY . .,把源码放后面 —— 源码频繁修改,但不影响前面的依赖层 - 合并多个
RUN命令(如RUN apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/*)减少层数并清理中间文件
精简运行镜像并加固安全基线
生产镜像不是越“全”越好,而是越“小”越稳。
- 优先选
-alpine镜像(体积通常只有-slim的 1/3),但注意某些 C++ 扩展可能不兼容,可测试后决定 - 添加非 root 用户:用
addgroup和adduser创建普通用户,再用USER切换上下文 - 通过
.dockerignore排除node_modules/、.git/、*.log、.env等,防止误传敏感或冗余文件 - 设置
WORKDIR权限、声明EXPOSE端口、用ENTRYPOINT+CMD明确启动逻辑
集成安全扫描与自动化验证
多阶段本身不等于安全,需配套机制保障交付质量。
- 在 CI 流水线中加入 Trivy 或 Docker Scout 扫描步骤,对最终镜像做 CVE 检查
- 启用 BuildKit(
DOCKER_BUILDKIT=1)获得更好的缓存导出/导入能力,支持远程构建复用 - 为镜像打语义化标签(如
v1.2.3、main-20260613),避免只用latest导致不可追溯 - 若需更高安全性,可进一步采用
distroless镜像(无 shell、无包管理器),仅含运行时依赖


















