国内镜像源实测:npm 从 38 秒降到 19 秒,Maven 从 185 秒降到 25 秒

约 6 分钟CInpmMaven镜像源NAS踩坑
文章目录 (7)

国内的 CI 机器直连 registry.npmjs.org 和 repo.maven.apache.org,偏偏每个 job 都是一只全新容器——上次的缓存一点留不下。两件事叠在一起,就是每次构建把整棵依赖树重下一遍。

这次换了两处源、加了缓存持久化,并把结果量化。下面所有数字都是控制变量实测:同一台机器、同一个镜像、同一棵依赖树、都从冷缓存开始。

一、先看数字

场景换源前换源后提速
Maven 冷解析
41.9 MB 依赖树
185 秒25 秒7.4×
npm 冷装
703 MB / 555 包
38 秒19 秒2.0×
npm 冷装 + 持久化缓存—16 秒2.4×

Maven 的差距比 npm 大得多:npm 官方源的 CDN 在国内其实还凑合,Maven Central 是真的慢。

二、npm

# <package.json 同级>/.npmrc
registry=https://registry.npmmirror.com/
audit=false
fund=false

不用重新生成 lockfile:npm 的 replace-registry-host 默认会把 lock 里指向 registry.npmjs.org 的地址自动改写。

三个坑:

  1. npm 不读父目录的 .npmrc。依赖不在根目录(又不是 workspace)时,每个 package.json 旁边都得放一份——判断标准是"哪个目录里执行 npm ci"。
  2. npm install 会改写 lockfile。npm ci 只读不改;但本地跑一次 install,lock 里的 resolved 就会被换成镜像地址,一次提交刷出几百行 diff。介意的话,改成只在 CI 里用 NPM_CONFIG_REGISTRY 环境变量。
  3. docker build 里要显式 COPY .npmrc ./,并确认 .dockerignore 和 .gitignore 都没把它排除掉。

三、Maven

<!-- ~/.m2/settings.xml -->
<mirror>
  <id>aliyun-public</id>
  <url>https://maven.aliyun.com/repository/public</url>
  <mirrorOf>*</mirrorOf>
</mirror>

Maven 自动读 ${user.home}/.m2/settings.xml,不用加命令行参数——比 npm 省心。

mirrorOf 写 * 会拦截所有仓库,包括你 pom.xml 里自己声明的那些。阿里云 public 聚合了 central 和 jcenter,常见场景够用;但要是依赖 spring-milestones 这类仓库,得改成 central,或写排除语法:*,!spring-milestones。

四、缓存持久化

换源解决"从哪下",挂载解决"下过的别再下":

-v /volume1/docker/_npm_cache:/root/.npm
-v /volume1/docker/_m2_cache:/root/.m2

npm 冷装从 19 秒进一步降到 16 秒;Maven 更明显,~/.m2 里躺的是整个本地仓库(我这边积累到 81 MB / 1481 个文件),下一次构建直接命中。顺便把 settings.xml 也放进这个目录,跟着一起挂进去就行。

五、最反直觉的一点:常规部署几乎不会变快

改造完去翻 CI 日志,发现很多次运行的总耗时前后没什么差别。两个原因:

1. Docker 层缓存本来就命中。 lockfile 没变时,日志里就是 Step 9/28 : RUN npm ci → ---> Using cache,整批镜像的构建阶段只花 3 秒。换源的收益只在"冷缓存"时兑现。

2. 依赖下载只占流水线一小部分。 拆开一次真实的 106 秒任务:

阶段耗时
Maven 打包55 s
npm ci(137 个包)5 s
部署与冒烟等待46 s

另一个前端项目整个任务 53 秒,npm ci 只占 8 秒(依赖才 101 个包)。

所以别拿"总耗时"当效果指标,它会把人误导到相反的方向——要看的是具体那一步的数字。

附带发现:让多个镜像共用一层缓存

monorepo 里 3 个 Dockerfile,如果依赖安装步骤的前缀不一致(copy 的文件顺序或数量不同),改一次 lockfile 就要下 3 遍。把它们改成逐字一致之后,RUN npm ci 变成同一个层,后两个镜像直接命中:

blog-web        Step 9/31 : RUN npm ci → ---> Using cache → ---> 24f64a37ef8e
blog-admin      Step 9/29 : RUN npm ci → ---> Using cache → ---> 24f64a37ef8e
blog-comments   Step 9/28 : RUN npm ci → ---> Using cache → ---> 24f64a37ef8e

三个镜像指向同一个层 ID,等于白拿一份"缓存挂载"的效果,而且不需要任何额外工具。

六、速查

# <package.json 同级>/.npmrc
registry=https://registry.npmmirror.com/
<!-- ~/.m2/settings.xml -->
<mirror>
  <id>aliyun-public</id>
  <url>https://maven.aliyun.com/repository/public</url>
  <mirrorOf>*</mirrorOf>
</mirror>
COPY .npmrc ./
RUN npm ci

同类还有腾讯云、华为云的公共镜像,配置方式完全一样(改 registry / mirror.url)——但我没实测,用之前建议自己测一下延迟。另外选源时留意同步延迟:刚发布的包镜像可能还没同步过去,那时报的 404 不是你配错了。

评论

纯文本,不支持链接/图片

加载评论…