有一个 node 项目使用 Dockerfile 构建出来的镜像达到了 2.4 G,实际上 node_modules 有 500 多 M, 基础镜像也只有几十 M, 代码则更少了。虽然镜像仓库有很多空间,这打出来的体积也太过于庞大,浪费空间,因此决定给它瘦身。
原始的 Dockerfile 内容如下:
FROM node:14.19.3-alpine3.16
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
WORKDIR /app
COPY package.json package-lock.json /app/
RUN npm install --registry https://registry.npmmirror.com
COPY . /app
RUN npm run build
CMD npm start
通过使用 docker history 命令看到,此处有两个问题,第一个是 npm install 执行的层体积过大, 达到了 1.5 G。第二个是 COPY . /app 执行层也达到了700多 M。

image.png
针对上面两个问题,执行瘦身的方式也很简单。第一个问题,使用 Docker 的多级构建即可,将原来一次性构建的方案,改为两级,第一级,先构建源码,得到构建内容;第二级,将第一级构建得到的内容 copy 过来即可。
修改之后的 Dockerfile 如下:
FROM node:14.19-alpine3.15 AS builder
WORKDIR /app
COPY package.json package-lock.json /app/
RUN npm install --registry https://registry.npmmirror.com
COPY . /app
RUN npm run build
FROM node:14.19-alpine3.15 AS runner
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
WORKDIR /app
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next ./.next. # nextjs 项目构建产出内容在 .next 目录下
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
CMD npm start
- 从
FROM node:14.19-alpine3.15 AS builder开始是第一级,只是为了通过RUN npm run build得到构建产物。 - 从
FROM node:14.19-alpine3.15 AS runner开始是第二级, 通过COPY --from=builder命令,从第一级镜像的对应目录中将所需要的内容复制过来即可。
第二个问题,则是需要在项目下添加 .dockerignore 文件,里面排除掉node_modules,确保 COPY 命令不会将 node_modules 目录包含进去(此处修改了 Dockerfile 之后,第二级构建并没有 COPY . /app 命令了,实际也不存在原来的问题了 )。
通过修改后的 Dockerfile 最终构建得到的镜像只有 700 多M,体积大小基本与实际情况吻合了。

image.png