Windows环境下Docker build执行RUN npm install后切换FROM步骤卡顿15分钟
你遇到的这个问题,核心原因大概率是第一个build-nodejs阶段生成的镜像体积过大——尤其是node_modules目录带来的成千上万小文件,导致Docker在完成该阶段的镜像提交、存储操作时耗时极长,这就是你看到的从第一个阶段所有RUN指令执行完成,到第二个FROM开始前的15分钟等待时间。
先澄清你的怀疑:node_modules不会意外传递到下一个阶段
Docker多阶段构建中,每个FROM指令都会启动一个全新的、独立的镜像阶段,默认情况下前一阶段的文件不会自动传递到后续阶段,除非你显式使用COPY --from=build-nodejs ...这样的指令。所以你的后续build-netcore阶段并没有继承node_modules,但前一阶段的大体积镜像本身会拖慢构建流程。
为什么切换阶段会耗时这么久?
当Docker完成一个阶段的所有指令后,它需要将该阶段的所有文件变更打包成新的镜像层,并提交到本地镜像仓库。对于Windows容器来说:
- Windows文件系统处理大量小文件的效率远低于Linux,而
node_modules通常包含海量小文件,这会导致镜像层的打包、写入磁盘过程变得非常缓慢。 - 如果你的第一个阶段还复制了不必要的文件(比如本地的
node_modules、.git目录、日志文件等),会进一步增大镜像体积,加剧这个问题。
针对性的优化方案
1. 用.dockerignore减少不必要的文件复制
在项目根目录创建.dockerignore文件,排除不需要复制到镜像中的内容:
node_modules/ .git/ *.log .vscode/
这样COPY . .只会复制必要的源码文件,避免本地的node_modules被重复复制到镜像里,减少初始镜像的大小。
2. 拆分指令,利用Docker缓存并减少镜像体积
调整build-nodejs阶段的指令顺序,先处理依赖安装,再复制源码,同时清理npm缓存:
FROM mcr.microsoft.com/windows/nanoserver:1809 AS build-nodejs WORKDIR /app # 先复制依赖描述文件,利用Docker缓存 COPY package*.json ./ ARG NODE_VERSION=12.10.0 RUN echo "Downloading NodeJS version %NODE_VERSION% ..." && \ curl "https://nodejs.org/dist/v%NODE_VERSION%/node-v%NODE_VERSION%-win-x64.zip" --output nodejs.zip && \ echo "Expanding NodeJS ..." && \ tar -xvf nodejs.zip -C "C:\\" RUN SET "PATH=%PATH%C:\\node-v%NODE_VERSION%-win-x64" && \ SET NODE_OPTIONS="--max_old_space_size=4096" && \ SET CI=true && \ npm install && \ # 清理npm缓存,减少镜像体积 npm cache clean --force # 最后复制剩余的源码文件 COPY . .
这样如果你的package.json没有变化,npm install的层会被缓存,不用每次都重新安装,同时清理缓存也能减少镜像的体积。
3. 只安装生产依赖(如果是生产环境构建)
如果你的构建是用于生产环境,可以添加--production参数跳过开发依赖的安装,大幅减少node_modules的大小:
npm install --production
4. 考虑切换到Linux容器(如果应用支持)
Linux容器的文件系统处理小文件的效率远高于Windows容器,如果你的应用可以在Linux环境下运行,建议切换到Linux版本的Node.js和.NET镜像,构建速度会有显著提升。
5. 验证第一个阶段的镜像体积
你可以运行docker images命令,找到build-nodejs阶段对应的镜像,查看它的体积。如果体积超过几个GB,那就能确认是镜像过大导致的提交耗时问题。
内容的提问来源于stack exchange,提问作者Ron G

