Docker 镜像瘦身与多阶段构建的实践总结

接手一个 Node.js 项目时,发现它的镜像高达 900MB,每次 CI 拉镜像都要等很久。排查后发现问题集中在两点:用了完整的重基础镜像,以及把构建依赖也打包进了最终镜像。用多阶段构建可以一并解决。

问题镜像长什么样

FROM node:18
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["node", "dist/server.js"]

node:18 完整镜像本身就接近 900MB,且 node_modules 里的 devDependencies 也被保留了下来。

多阶段构建

FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]

核心思路:在 builder 阶段完成所有重活(安装依赖、编译),最终镜像只拷贝运行所需的 dist 和精简后的依赖。

继续瘦身

RUN apk add --no-cache curl \
    && rm -rf /var/cache/apk/*

收益

优化后镜像从 900MB 降到 120MB,CI 构建和部署时间缩短了约 70%。更重要的是,攻击面也大幅缩小——镜像里不再有编译工具链和测试文件。

小结

多阶段构建是 Docker 最值得掌握的技巧之一。它把「构建环境」和「运行环境」彻底分离,让你鱼和熊掌兼得。