跳到主要内容

Docker 多阶段构建优化 Node.js 镜像

· 阅读需 3 分钟
一介布衣
全栈开发者 / 技术写作者

容器化到 2022 年已经是很普遍的工程实践了,但很多团队在真正上线 Node.js 服务时,还是会遇到一个很现实的问题:镜像能打出来,但体积太大、构建太慢、部署不够干净。

多阶段构建最直接的价值

它帮助我们把:

  • 构建环境
  • 运行环境

明确拆开。这样最终镜像里只保留真正运行需要的部分。

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

FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/build ./build
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "build/index.js"]

这种做法最直接的收益就是把“编译依赖”留在 builder 阶段,而不是一股脑打进最终镜像。这样发布出来的镜像通常更小、更干净,线上环境里也更容易控制运行风险。

还可以顺手注意两件事

  • 先复制 package.json 和 lockfile,再安装依赖,能更好利用缓存
  • 如果运行阶段不需要完整依赖,可以进一步只保留生产依赖

这些细节单独看都不大,但叠在一起,对 Node.js 服务的构建速度和镜像体积会很有帮助。

多阶段构建真正解决的不是“看起来高级”

它更像是在明确一条边界:构建阶段需要很多工具、编译产物和缓存,但运行阶段真正需要的只有少量可执行内容。把这两者分开之后,镜像不仅更小,也更容易理解和维护。对团队来说,这种清晰度本身就是价值。

很多上线问题最后都会落到“镜像到底装了什么”上,而多阶段构建恰好是在最前面帮你把这件事理顺了。

小结

Docker 多阶段构建在 2022 年已经不只是一个“优化技巧”,而是很多 Node.js 项目走向更稳部署的基础能力之一。

对团队来说,这种构建方式还有一个长期收益:构建规则一旦稳定下来,后面的项目几乎都可以复用。也就是说,你不是每做一个 Node.js 服务都重新摸索一次镜像结构,而是把多阶段构建慢慢沉淀成一条团队级的部署习惯。

这也是为什么很多团队在把服务容器化做到一定阶段之后,会开始非常重视 Dockerfile 的可读性和一致性。镜像不只是能跑就行,它同时也是部署知识的载体。越清楚的构建分层,后面越容易复制成功经验,也越不容易在新项目里重复踩旧坑。