TT Lab
开始
学习 学习路径 课程

隔离网络镜像与私有 CA

为什么要再搭一个仓库

在 TT Lab 中继续学习

一句话总结

npm 应对隔离网络的办法,就是再搭建一个 registry。联网期间从上游(npmjs)拉取并填充,断开之后只提供已填充的内容。项目通过 .npmrc 中的一行 registry 指向该 registry。锁文件中写死的地址,npm 会自动替换,但如果不了解这个默认行为,就会出事故。

为什么需要它

一个前端仓库的 node_modules 就有几百个软件包。在隔离网络中执行 npm ci,在第一个软件包处就会停住。常见的临时办法,是在联网的 PC 上把 node_modules 整体压缩后带进去,但如果操作系统或 node 版本不同,原生模块就会损坏,而且也不会留下带进去了什么的清单。需要的是一个可以按软件包为单位下载保存、并能按锁文件重新安装的仓库。

工作原理

指向 registry。 npm 按命令行 → 环境变量 → npmrc 文件 → 默认值的顺序遵循配置,而 npmrc 按项目(.npmrc)→ 用户(~/.npmrc)→ 全局($PREFIX/etc/npmrc)→ 内置的顺序具有优先级。registry 的默认值是 https://registry.npmjs.org/。在项目的 .npmrc 中写入 registry= 后,无论谁打开这个仓库,看到的都是同一个 registry。

verdaccio 的三项配置。 uplinks 是上游 registry 的列表,packages 则按名称模式分别确定 access、publish、proxy。根据文档,模式的顺序很重要,并把 ** 放在最后兜底。在 proxy 中写了 uplink 名称的模式,会把本地没有的内容从上游拉取并留存到 storage 中,而没有 proxy 的模式只提供本地仓库中已有的内容。 这就是“断开”的真正含义。默认端口是 4873。

换成 Nexus 或 Artifactory 的术语就是这样。Nexus 文档把仓库分为三种——缓存远程内容的 proxy、由我们上传的原件 hosted,以及把多个仓库合并到一个地址的 group。verdaccio 中带有 proxy: npmjs 的模式相当于 proxy 仓库,对内部软件包执行 publish 的模式相当于 hosted,把两者合并到一个地址提供的,则承担 group 的角色。Nexus 3 的官方要求规格是主机内存 8GB、默认堆 2703MB,放不进本实验 Pod(2Gi)。用轻量的工具掌握原理,再对应到现场设备的菜单就行。

锁文件和地址。 package-lock.json 的 resolved 中写着 tarball 的完整地址。在外部生成的锁文件里,写死了 https://registry.npmjs.org/...。npm 的 replace-registry-host 设置就是处理这个问题的。默认值 npmjs 会把指向默认 registry 的地址替换为所设置的 registry 后再下载。never 会按所写的地址原样访问,always 则不论是什么主机都替换。这也意味着,把写着某个内部 registry 地址的锁文件迁到另一个内部 registry 时,默认值帮不上忙。

安装命令。 npm ci 要求必须有锁文件,与 package.json 不一致时不会修改锁文件,而是报错停止,并会删除 node_modules 后重新安装。导入复现应该用这个。--offline 完全不发出网络请求,只使用缓存,--prefer-offline 优先查看缓存,没有才去下载。npm 文档写道,不要指望缓存是可靠的持久存储——这就是为什么要搭建 registry,而不是把缓存当作导入手段。

在现场相遇的样子

我们在这个实验 Pod 中实测过(npm 10.9.0,verdaccio 6.1.6)。用写死了 registry.npmjs.org 地址的锁文件,在外部被封闭的状态下执行 npm ci --registry http://127.0.0.1:4873/,默认值下有 6 个软件包从内部 registry 安装成功,而加上 --replace-registry-host=never 后,则因代理连接错误而停止。同一个锁文件、同样的 registry 设置,一行默认值就决定了结果。另外,向断开了 uplink 的 verdaccio 请求仓库中原本没有的软件包,会返回 404。这不是“registry 出故障了”,而是“不在导入清单上”,所以 404 是要你重写导入申请单的信号。

verdaccio 本身也是 npm 软件包,所以同样是导入物。在本实验中安装它,会附带 270 多个依赖,占用 59MB 磁盘。只有固定版本安装,并把它的锁文件一并保存,才能在隔离网络内重新搭建出同一个 verdaccio。

下一项实验要做什么

安装 verdaccio 6.1.6,把 npmjs 作为上游搭建 registry,以 npm.airgap.internal:4873 启动,用项目的 .npmrc 指向它,并拉取填充 chalk 4.1.2。断开 uplink 后,评分器会在外部被封闭的状态下,用新缓存重新运行 npm ci,看是否成功。最后用在外部生成的锁文件,亲自比较并记录 replace-registry-host 的默认值与 never。

参考文档:npmrc、npm config(registry、replace-registry-host、offline)、npm ci、verdaccio Configuration、verdaccio Packages、Nexus Repository Types、Nexus System Requirements