拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Nexus3 私库实战:Maven、Yum、Apt、npm 四类仓库配置与避坑

1. 私库的真实收益从一次 CI 卡住说起上周帮一个团队看构建问题现象很典型流水线上某个 Java 服务突然构建失败报错是拉不到一个三方依赖而本机开发的同学重跑一遍又好了。查下去发现是外网源偶发抖动本地有.m2缓存所以没事干净容器里没有缓存就直接挂。这类问题只要出现过一次团队里就会有人提要不我们搭个nexus3 私库吧。这个提议基本不会错但真正落地的时候绝大多数人卡的不是安装而是四种包格式maven、yum、apt、nodejs各自的仓库怎么建、客户端怎么指、出错了往哪查。我自己维护过一套同时承载 Maven、RPM、Debian 包和 npm 的 Nexus3也见过只用来缓存 Maven 的轻量部署。两种都成立区别在于你要不要为离线可构建这件事买单。Nexus3 的价值说白了就四块把公网依赖缓存到内网、在没有外网的机器上照样装包、把公司自研的构件集中托管、让所有依赖走同一个出口便于审计和限流。它不是一个加速器插件而是一个制品仓库服务理解这一点后面很多配置上的反直觉就顺了。提示Nexus3 的社区版OSS已经覆盖 maven2、yum、apt、npm、raw、docker、pypi 等主流格式不需要为多格式能力额外付费。真正需要评估的是版本差异有些格式的 hosted 支持是后期才补齐的。1.1 没有私库时团队在哪些地方持续流血最容易被忽略的成本是重装环境。一个新人入职第一件事是配 Maven、配 npm、配 yum 源如果全靠公网网络状况一差就是半天。第二块成本是 CI 的稳定性公网源的 SLA 你控制不了镜像站偶尔同步延迟几分钟你的发布窗口就可能被卡。第三块是自研构件的分发内部 SDK 靠install:install-file手工塞进本地仓库版本一多就没人说得清线上跑的是哪一版。第四块是合规与审计到底哪些外部依赖被引入了、谁在什么时候拉了什么包没有统一出口时几乎查不出来。这四块成本叠加起来一次生产事故的排查代价就够买几台机器了。所以判断标准很简单只要团队里有超过三个人在写同一种语言的代码或者存在任何一个不能直接出网的环境私库就值得上。1.2 一套 Nexus3 能不能同时喂饱四种包格式能而且这是 Nexus3 相对其他方案最舒服的地方一个进程、一个端口、一套账号体系把 Java、Linux 系统包、Debian 包和前端依赖全收进去。需要提前想清楚的是磁盘和内存的分配因为这四种格式的体积量级差得很远。包格式单套上游体积量级私库里的典型增长来源内存敏感度maven2全量十几 TB实际只缓存被请求的团队日常构建、CI 每次全新构建中元数据索引较多yum单发行版 4 到 10 GB多发行版、多架构叠加很快低apt单发行版 3 到 8 GB第三方源如 ROS、显卡驱动源另算低npm全量 TB 级实际缓存的较小前端项目多、node_modules反复重建中包数量极多、单包很小看这张表就能得出一个结论磁盘要给足但内存不用按磁盘线性放大。真正吃内存的是并发请求数和包元数据索引一台 8 核 / 16 GB 的机器撑一个几十人团队绰绰有余前提是 JVM 堆别配得太小。2. 上线前的资源盘点和目录规划我见过太多人下载完 tarball 直接tar -zxvf到/root里跑起来能跑通但三件事会立刻找上门磁盘被写满在系统盘、升级时数据目录找不到、进程被CtrlC之后重建索引。花十分钟把目录和账号规划好后面能省掉几小时的救火。2.1 JDK 版本和 Nexus 版本的对应关系Nexus3 的运行依赖 JDK这里的坑是版本对不上直接启动失败而且日志里只有一行看不懂的异常。经验做法是比较老的 3.2x 系列用 JDK 8 就够较新的 3.3x 之后官方逐步推荐 JDK 11部分新版本已经不再支持 JDK 8。先查发行说明再装 JDK别反过来。# 确认本机 JDK 版本不要用 JRENexus 启动脚本会检查 java 可执行文件 java -version readlink -f $(which java) # 如果机器上有多个 JDK用环境变量锁定 Nexus 使用哪一个 export JAVA_HOME/usr/lib/jvm/java-11-openjdk提示服务器上同时跑着别的 Java 应用时不要改全局JAVA_HOME直接在 Nexus 的启动脚本或 systemd 单元里指定EnvironmentJAVA_HOME...避免互相影响。2.2 磁盘、内存、端口三件事怎么定磁盘上我习惯给 Nexus 单独挂一块盘或者单独一个 LVM 卷挂载到/data。这样做的实际好处是磁盘告警、扩容、快照都不影响系统盘出问题时也容易判断是不是又被缓存撑爆了。如果是四格式全开起步建议 200 GB前端团队大、或者要托管多套发行版 ISO 的场景给到 500 GB 更从容。内存上Nexus 的 JVM 参数写在bin/nexus.vmoptions里默认大概是-Xms2703m -Xmx2703m再加一个等值的MaxDirectMemorySize。这个默认值是给轻量场景准备的四格式全开加上多任务并发我一般会调到 4 GB 到 8 GB同时保证物理内存比堆多出 2 GB 以上留给操作系统文件缓存和堆外内存。# /opt/nexus/bin/nexus.vmoptions 摘录 -Xms4096m -Xmx4096m -XX:MaxDirectMemorySize4096m -XX:UnlockDiagnosticVMOptions -Dkaraf.data/data/nexus-data -Djava.io.tmpdir/data/nexus-data/tmp最后一行特别值得留意-Dkaraf.data决定数据目录位置默认会落在安装目录同级的一个sonatype-work/nexus3下。如果你把安装目录放在/opt数据实际写在/opt/sonatype-work系统盘很容易被写满所以我通常显式改成/data/nexus-data。端口方面Nexus 默认监听 8081配置在etc/nexus-default.properties里可以改application-port、application-host和nexus-context-path。如果前面要挂反向代理建议保持 8081 只监听127.0.0.1对外走 80 或 443。2.3 用 systemd 托管别用 nohup 硬扛裸跑的问题是重启后不会自恢复而且nexus start会 fork 出子进程用nohup包一层经常出现主进程活着但子进程死了的假象。标准做法是写一个 systemd 单元# /etc/systemd/system/nexus.service [Unit] DescriptionNexus Repository Manager Afternetwork.target [Service] Typeforking LimitNOFILE65536 Usernexus Groupnexus EnvironmentJAVA_HOME/usr/lib/jvm/java-11-openjdk ExecStart/opt/nexus/bin/nexus start ExecStop/opt/nexus/bin/nexus stop Restarton-abort TimeoutSec600 [Install] WantedBymulti-user.target注意LimitNOFILE65536Nexus 并发连接较多时默认的 1024 会不够用表现为偶发连接被拒但日志里几乎看不出原因。另外建议单独建一个nexus系统账号来跑root 直接运行会被启动脚本拦下来或给出强烈警告。3. Nexus3 装完到能用之间还差这几步解压、启动、拿到初始密码这三步是所有人都会做的。但真正决定这套私库能不能长期用的是接下来那几步安全配置它们不写进任何快速上手文档却是踩坑高发区。3.1 初始密码在哪以及为什么要立刻改掉启动之后初始管理员密码在数据目录下的admin.password文件里。注意这个路径取决于你前面设置的-Dkaraf.data很多人按默认路径去找结果找不到。# 假设数据目录已改为 /data/nexus-data cat /data/nexus-data/admin.password # 用完之后这个文件会失效建议顺手确认它已经不在了 ls -l /data/nexus-data/admin.password首次登录会强制改密码。改完之后立刻做两件事一是建一个专门用来部署的账号不要用 admin 去做mvn deploy二是确认匿名访问是否符合你的预期。Nexus3 默认开启匿名访问并给匿名角色授予所有仓库的读权限。内网环境下这样最省事客户端不用配凭据如果你想统计谁拉了什么包就得关掉匿名访问然后给每台机器配独立账号代价是所有 Maven、npm、yum 客户端都要带上凭据。3.2 Realm 开关npm 和 docker 用户必看这一项我踩过而且踩的时候完全不知道是它的问题。Nexus3 的认证机制是一组 Realm 插件默认只开了几个基础的。用npm login时如果不打开npm Bearer Token Realm你会一直收到 401但用浏览器登录同一个账号却是好的非常迷惑。操作路径是Security→Realms把需要的 Realm 从 Available 移到 Activenpm Bearer Token Realmnpm 登录和发布必须Docker Bearer Token Realm要托管镜像仓库时再开Local Authenticating Realm / Default Realm保持开启否则本地账号登不进来改完 Realm 需要重新登录一次。这个动作我记得很清楚因为当时排查了一个小时最后发现是 Realm 列表里少勾了一项。3.3 反向代理与 Base URLnpm 用户的重灾区如果前面挂了 Nginx 做 HTTPS 和域名有一个配置项必须补上Base URL Capability。原因是 npm 的包元数据里包含 tarball 的完整下载地址这个地址由 Nexus 自己生成。如果不告诉它你对外暴露的地址是什么它就会按请求时的 Host 头或者本机 8081 端口生成导致客户端拿到一个内网端口地址走到一半就 404。Nginx 侧的最小配置大概是这样server { listen 443 ssl; server_name nexus.internal.example.com; ssl_certificate /etc/nginx/certs/nexus.crt; ssl_certificate_key /etc/nginx/certs/nexus.key; # 大构件上传比如 RPM、大的前端包需要放开这个限制 client_max_body_size 2048m; location / { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 缓存的首次拉取可能很慢别让代理先超时 proxy_read_timeout 900s; proxy_send_timeout 900s; } }然后在 Nexus 的System→Capabilities里新建一个Base URL能力填上https://nexus.internal.example.com。这一步做完npm 的 tarball 地址才会正确。4. proxy、hosted、group把仓库类型想成三层结构Nexus3 里每建一个仓库第一步都要选类型很多人在这里犹豫因为三个选项看起来都像仓库。我用一个生活类比来解释proxy 是外卖代购hosted 是自家冰箱group 是取餐窗口。代购负责去外面的店把东西买回来存着冰箱负责存你自己做的东西取餐窗口就是把两者摆在一起让客户端只记一个地址。理解这个类比后面所有配置都能自己推导出来。4.1 proxy 是缓存不是实时镜像proxy 仓库的关键参数是Remote storage上游地址它决定了 Nexus 去哪里抓包。抓回来的东西存在本地 blob store 里下次同样请求直接命中缓存。这里有两个常被误解的点第一proxy不会主动全量同步你不请求它就不下载所以磁盘增长是渐进的第二缓存的过期策略由Negative Cache TTL和 HTTP 缓存头共同决定公网源返回 404 时也会被短时间缓存这就是为什么有些包你刚发到公网、通过私库却拉不到过几分钟又好了。Remote storage 的写法有讲究一定要指向包含元数据目录的那一层。Maven 要指向包含org/、com/的根通常是https://repo1.maven.org/maven2/yum 要指向包含repodata/的那一层apt 要指向包含dists/和pool/的根。指向错了不会立刻报错而是会不断返回 404并在 Nexus 里留下一堆负面缓存。4.2 hosted 是自留地release 与 snapshot 必须分开hosted 仓库是未来放自研构件的地方。Maven 场景下我强烈建议建两个host 仓库一个maven-releases设为 Release 版本策略一个maven-snapshots设为 Snapshot 版本策略。混在一个仓库里的后果是某天一个正式版本被同名快照覆盖或者发布流水线把错误的策略传给了 Nexus返回一个 400全组一起去查原因。yum 和 npm 的 hosted 仓库同样有一些开关值得注意。yum hosted 有一个Deployment policy测试期建议设成Allow redeploy否则同一个 RPM 想重新上传会被拒绝而 RPM 的版本号一旦写死就不能改了只能靠加 release 号绕过。npm hosted 默认不允许覆盖已发布的版本这是有意为之的设计别轻易关掉。4.3 group 只负责聚合读流量group 仓库本身不存东西它只是一个成员列表并且按顺序匹配请求进来后先从第一个成员找找到了就返回找不到才往后走。所以顺序需要按业务意图排内部构件优先时把 hosted 放前面纯粹当公共代理用时把代理放前面。还有一个新手最容易犯的错部署deploy / publish / upload不能指向 group。group 是只读的聚合视图往它上面mvn deploy会返回 405 或者 400而报错信息不会明确告诉你你指错仓库类型了。记住这条就够了读走 group写走 hosted。5. Maven 私库落地从 mirror 配置到 mvn deployMaven 是 Nexus 最经典的用法配置看起来就改一个settings.xml但实际踩坑密度最高。我把完整链路拆成三段建仓库、配客户端拉取、配客户端发布。5.1 三个仓库的搭建顺序与 URL 形态标准做法是建三个仓库maven-centralproxy指向公共中央仓库或国内镜像、maven-releaseshosted、maven-snapshotshosted最后建maven-publicgroup把三者聚合。建完之后你会得到三种 URL形态上很容易混淆仓库类型典型 URL用途maven-centralproxyhttps://nexus.internal/repository/maven-central/只给 Nexus 内部用客户端一般不直连maven-releaseshostedhttps://nexus.internal/repository/maven-releases/正式版本发布目标maven-snapshotshostedhttps://nexus.internal/repository/maven-snapshots/快照版本发布目标maven-publicgrouphttps://nexus.internal/repository/maven-public/客户端唯一读取入口URL 结尾的那个斜杠很重要少了它某些客户端版本会把最后一段当成文件名表现是拉元数据时路径拼错。5.2 settings.xml 里 mirrorOf 写错会把所有仓库都劫持这是我最想提醒的一条。很多教程直接给mirrorOf填一个*意思是所有仓库都走 Nexus。这个写法在只有中央仓库的项目里没问题但它同时会劫持项目pom.xml里显式声明的第三方仓库比如某个公司自己维护的 Maven 仓库而你的 Nexus 里并没有对应的代理结果就是明明能拉的包突然拉不到了。mirrors mirror idnexus-public/id !-- 只劫持外部源localhost 和 file:// 保持原样 -- mirrorOfexternal:*/mirrorOf urlhttps://nexus.internal.example.com/repository/maven-public//url /mirror /mirrors如果团队情况简单只写mirrorOfcentral/mirrorOf更保守只替换中央仓库其他仓库声明照常走原地址。两种都可以关键是别盲目抄*。5.3 发布内部构件id 必须和凭据对上发布配置分两处项目pom.xml里写目标地址settings.xml里写凭据。两者的连接点是id 字符串必须完全一致这是 401 报错最主要的原因。!-- 项目 pom.xml -- distributionManagement repository idnexus-releases/id urlhttps://nexus.internal.example.com/repository/maven-releases//url /repository snapshotRepository idnexus-snapshots/id urlhttps://nexus.internal.example.com/repository/maven-snapshots//url /snapshotRepository /distributionManagement!-- ~/.m2/settings.xml -- servers server idnexus-releases/id usernameci-deploy/username password你的密码或令牌/password /server server idnexus-snapshots/id usernameci-deploy/username password你的密码或令牌/password /server /serversid 对不上时Maven 找不到匹配的 server 配置于是发出匿名请求Nexus 返回 401。测试期可以先用mvn deploy -X看 Maven 实际发出的请求地址和目标仓库 id一眼就能看出来。5.4 部署阶段几个高频报错的对应关系把常见报错和根因列成一张表比反复翻日志快得多报错片段根因处理方式Return code is: 401id 不匹配、密码错、账号无写权限核对 server id检查角色是否有对应仓库的nx-repository-admin-*或写权限Return code is: 405部署目标填成了 group 或 proxy改成 hosted 仓库地址Repository version policy: RELEASE does not allow ...往 release 仓库推快照或反之检查版本号后缀-SNAPSHOT必须进 snapshot 仓库拉不到刚发布的包本地.lastUpdated缓存了失败结果删除~/.m2/repository下对应目录的*.lastUpdated或用mvn -U强制刷新部署卡住后失败大构件上传被 Nginx 体积限制拦截提高client_max_body_size并加大proxy_read_timeout那个.lastUpdated的坑特别值得说。Maven 在拉取失败时会生成一个时间戳文件在一段时间内不再重试。所以我在 Nexus 里明明看到包了本地就是拉不到这种情况八成是它。脚本化处理find ~/.m2/repository -name *.lastUpdated -delete mvn -U clean package6. Yum 私库本地 ISO、上游代理与自研 RPM 的合流Yum 这块的需求往往比 Maven 更刚生产环境不能出网但服务器要装监控代理、要打安全补丁、要装自研的运维工具包。Nexus 的 yum 格式能把这三类来源合到一个baseurl上客户端配置极简。6.1 remote storage 要指到 repodata 那一层建 proxy 仓库时Remote storage 必须指向直接包含repodata/目录的地址不是发行版的根。举几个实际例子体会一下差别某个 7 系列发行版的基础源指到.../centos/7/os/x86_64/更新源指到.../centos/7/updates/x86_64/较新的发行版把基础包和模块包拆成了两个独立仓库BaseOS 和 AppStream两者各有自己的repodata/所以必须建两个 proxy 仓库再用一个 group 把它们合起来第二点经常被忽略。有人只代理了 BaseOS然后发现装某些开发工具包时提示找不到其实是 AppStream 没代理。判断方法很直接去上游站点看一眼哪个目录下有repodata/就给它建一个 proxy。6.2 把本地 ISO 变成私库里的一个源离线场景最现实的素材是发行版安装 ISO它本身就是一套完整的 yum 源。有三种处理方式各有取舍第一种客户端直接挂载 ISO。优点是零改造缺点是每台机器都要有一份 ISO、都要手动挂载而且容器里挂不了。mkdir -p /mnt/iso mount -o loop /data/CentOS-7-x86_64-DVD-2009.iso /mnt/iso # 客户端 repo 文件里写 file:///mnt/iso第二种把 ISO 里的 Packages 上传到 Nexus 的 hosted yum 仓库。这是我最推荐的方式一次上传所有机器都能用也能被容器访问。缺点是初始上传耗时几 GB 的 RPM 数量在几千个量级界面批量上传容易中断建议分批或者用 REST 接口。第三种在中间搭一个静态文件服务用createrepo重建索引后让客户端指向它。这适合你已经在用 Nginx 提供其他静态资源的场景但对 Nexus 用户来说是重复建设。提示如果只是想让安装系统时能选到本地源那在安装介质里做 kickstart 更合适Nexus 私库解决的是装机之后长期的、跨机器的包获取问题。6.3 自研 RPM 上传与 repodata 的自动生成Nexus 的 yum hosted 仓库有一个很省心的特性上传 RPM 之后会自动重建 repodata不需要你在服务器上装createrepo手动跑。界面路径是进入仓库后点Upload可以多选一批.rpm一起传。批量场景下用 REST 接口更稳参数名以你所用版本的 API 文档为准yum 格式大致是这样curl -v -u ci-deploy:密码 \ -F yum.asset./ops-agent-2.3.1-1.el7.x86_64.rpm \ -F yum.asset.filenameops-agent-2.3.1-1.el7.x86_64.rpm \ https://nexus.internal.example.com/service/rest/v1/components?repositoryyum-hosted如果确实需要在 Nexus 之外维护一套 RPM 目录比如从 ISO 里筛出子集那就必须自己重建索引# 在存放 RPM 的目录下执行生成 repodata/ createrepo -v /data/myrepo # 后续增删了 RPM用 --update 增量刷新比全量重跑快很多 createrepo --update /data/myrepo6.4 客户端 repo 文件与缓存刷新客户端侧要做的就是写一个 repo 文件指向 group 仓库。我一般建议用 group把上游 proxy 和自研 hosted 合起来这样一台机器只需要一个源。# /etc/yum.repos.d/nexus.repo [nexus-all] nameNexus All Packages baseurlhttps://nexus.internal.example.com/repository/yum-group/ enabled1 gpgcheck0gpgcheck0在内网很常见但它意味着不校验包签名。更稳妥的做法是把上游的 GPG 公钥也作为一个文件放到 raw 仓库里然后gpgkey指向它、gpgcheck1。另外要提醒的是Nexus 缓存的上游元数据有 TTL客户端刚配置完如果报找不到包先做一次强制刷新别急着怀疑配置。yum clean all yum makecache yum repolist -v如果yum makecache报元数据下载失败通常就三个方向baseurl 拼错尤其是少了或多了路径层级、group 里成员顺序有问题导致先命中了空仓库、以及 HTTPS 证书不被信任内网自签证书要额外导入。7. Apt 私库不同 Nexus 版本的能力差异与兜底方案Apt 这块是四者中最需要看版本说话的。Nexus3 对 apt 的支持是逐步补齐的proxy 相对成熟hosted 在很多版本里并没有开放所以实际落地时往往需要一条兜底路线。先把预期建立起来再动手。7.1 apt proxy 的指向与签名校验proxy 仓库的 Remote storage 要指向包含dists/和pool/的根目录比如某个 Ubuntu 镜像的根或者packages.ros.org/ros/ubuntu这种第三方源根路径。然后在客户端的 sources 列表里把发行版代号和组件写清楚# /etc/apt/sources.list.d/nexus.list deb https://nexus.internal.example.com/repository/apt-ubuntu/ focal main restricted universe multiverse deb https://nexus.internal.example.com/repository/apt-ros/ focal main这里的focal是发行版代号它对应上游dists/focal/这个目录。代号写错了就是 404报错信息里会带上完整路径对着找一下就能定位。真正麻烦的是签名。Apt 会校验 Release 文件的 GPG 签名如果缺公钥会明确报public key is not available。内网环境没法直接联网取密钥但有个很省事的办法任何一台已装好的同发行版机器上公钥文件本来就在系统里直接拷过来即可。# 从一台现成的同发行版机器上拷贝路径是系统自带的不需要联网 cp /usr/share/keyrings/ubuntu-archive-keyring.gpg /etc/apt/trusted.gpg.d/ # 如果是第三方源比如 ROS把对应的 keyring 文件也一起放进去 ls /usr/share/keyrings/ | grep -i ros如果确实取不到公钥可以在方括号里加trustedyes跳过校验。这条路能走通但它等于放弃了完整性验证只适合完全隔离、可控的内网别把它当成常规配置传播。7.2 当你的版本没有 apt hosted 时怎么办这是最容易让人卡住的一步你想把自研的.deb也托管进来却发现仓库类型里根本没有 apt 的 hosted 选项。这时候别硬等版本升级用raw 仓库 扁平仓库布局就能解决而且非常稳定。原理很简单Apt 支持一种扁平仓库布局只要在指定路径下能找到Packages.gz就能被识别成一个源。我们要做的就是自己生成这个索引文件然后把它和.deb一起放进 raw 仓库。# 1. 准备目录把所有 .deb 放进去 mkdir -p /tmp/flatrepo cp /data/builds/*.deb /tmp/flatrepo/ cd /tmp/flatrepo # 2. 生成扁平布局的索引./ 表示当前目录即仓库根 dpkg-scanpackages -m ./ /dev/null | gzip -9c Packages.gz # 3. 把 Packages.gz 和所有 .deb 一起上传到 raw 仓库可用界面批量上传也可用 REST ls -lh Packages.gz客户端侧用./明确告诉 Apt 这是扁平布局而不是标准布局# /etc/apt/sources.list.d/internal-deb.list deb [trustedyes archamd64] https://nexus.internal.example.com/repository/raw-debs/ ./提示archamd64建议写上否则 Apt 会尝试去请求其他架构的索引日志里会出现一堆没有实际影响的跳过提示但会干扰排查。如果不想用trustedyes可以进一步做成签名仓库用apt-ftparchive release生成 Release 文件再用 GPG 生成Release.gpg和InRelease一并上传然后把公钥导入客户端。多花十分钟换来的是可校验的完整性值不值取决于你的合规要求。7.3 apt 客户端常见报错速查报错片段根因处理public key is not available缺少上游公钥拷贝 keyring 到/etc/apt/trusted.gpg.d/或临时trustedyesRelease file ... is not valid yet客户端与服务器时间偏差同步时间偏差超过几分钟就会触发404 Not Found且路径带 dists发行版代号或组件名写错对着上游dists/目录核对Skipping acquire of configured file main/binary-i386/Packages未限定架构加archamd64更新极慢但最终成功首次缓存冷启动所有索引都要回源属正常现象第二次会明显变快时间偏差这一条我特别想强调因为它看起来跟私库毫无关系。内网服务器常见时间漂移Apt 的签名有效期校验很敏感一偏就全盘失败。8. Node.js / npm 私库registry 切换、发布与离线包托管前端这块的需求和 Maven 有点像但依赖数量大得多一个中型项目node_modules里上千个包很常见走公网源每次全新安装都在赌网络。npm 私库带来的提速体感在这四种格式里通常是最明显的。8.1 三个仓库与客户端 registry 的写法和 Maven 一样的三件套npm-proxy指向公共 npm 源、npm-hosted自研包、npm-group聚合。group 里的成员顺序建议把 hosted 放前面这样内部包名和公共包名撞车时优先命中自己的避免供应链混淆。客户端配置有两种粒度。全局配置写在用户级.npmrc里项目级配置写在项目根目录的.npmrc里——项目级的优先级更高我在团队里统一推行项目级配置好处是换了机器不用重新配而且 CI 里天然生效。# 项目根目录 .npmrc registryhttps://nexus.internal.example.com/repository/npm-group/ # 作用域包单独指向内部仓库避免发错地方 mycompany:registryhttps://nexus.internal.example.com/repository/npm-hosted/ strict-ssltrue如果把strict-ssl设成false来绕过自签证书会同时关掉所有 HTTPS 校验我的建议是宁可把内网 CA 装到系统信任链里也不要关这个开关。8.2 npm login 与 Bearer Token Realm发布内部包需要先登录。这里就是前面提到的 Realm 坑没开 npm Bearer Token Realm登录一定失败。登录命令和发布命令分别是npm login --registryhttps://nexus.internal.example.com/repository/npm-hosted/ # 依次输入用户名、密码、邮箱 # 发布时显式指定 registry别依赖默认值 npm publish --registryhttps://nexus.internal.example.com/repository/npm-hosted/更省事的做法是在package.json里写死发布目标这样团队成员直接npm publish就不会发错{ name: mycompany/utils, version: 1.4.2, publishConfig: { registry: https://nexus.internal.example.com/repository/npm-hosted/ } }两个高频报错npm ERR! code E401 Unable to authenticateRealm 没开或者账号密码不对。npm ERR! 403 Forbidden - PUT ... does not allow updating assets同一个版本号重复发布。npm 的哲学是版本不可变正确做法是升版本号而不是去开覆盖权限。真要覆盖只能在 hosted 仓库设置里调整 deployment policy但我不建议在生产仓库这么做。8.3 用 raw 仓库解决 Node.js 本体的离线安装包的问题解决了还有个前置问题那台不能出网的机器上Node.js 运行时本身怎么装答案是用 Nexus 的 raw 仓库托管二进制包这是很多人没想到但极其好用的一招。# 在能出网的机器上下载好上传到 raw 仓库的 nodejs/ 目录 # 目标机器上直接拉取 curl -O https://nexus.internal.example.com/repository/raw-binaries/nodejs/node-v18.20.4-linux-x64.tar.xz tar -xJf node-v18.20.4-linux-x64.tar.xz -C /usr/local/lib ln -sfn /usr/local/lib/node-v18.20.4-linux-x64 /usr/local/lib/nodejs# 写入 profile注意把 lib/nodejs 放在 PATH 靠前位置 cat /etc/profile.d/nodejs.sh EOF export NODE_HOME/usr/local/lib/nodejs export PATH$NODE_HOME/bin:$PATH EOF source /etc/profile.d/nodejs.sh node -v npm -v如果团队用 nvm 管理多版本nvm 支持通过环境变量改下载镜像地址。这里有个细节nvm 会按v版本号/这一层目录去找文件所以上传到 raw 仓库时要建对应的子目录否则它会一直 404。export NVM_NODEJS_ORG_MIRRORhttps://nexus.internal.example.com/repository/raw-binaries/nodejs # 对应的目录结构应是 .../nodejs/v18.20.4/node-v18.20.4-linux-x64.tar.xz8.4 客户端环境里的两个小麻烦第一个是 npm 自身的本地缓存。私库已经把下载慢解决了但node_modules的写入开销还在。CI 里如果每次都全新安装可以考虑缓存~/.npm目录让解压阶段也省掉一部分时间。第二个问题出现在 Windows 开发机上执行npm时报无法加载文件 ... npm.ps1因为在此系统上禁止运行脚本。这不是 Nexus 的问题是 PowerShell 执行策略拦下了 npm 的包装脚本。两种处理方式任选其一# 方式一调整当前用户的执行策略管理员 PowerShell 中执行 Set-ExecutionPolicy -Scope CurrentUser RemoteSigned # 方式二不改策略直接用 cmd 版本的可执行文件 npm.cmd install团队内我一般推荐方式二改动最小也不会影响其他脚本的安全策略。9. 跑起来之后清理、备份与故障速查私库上线只是开始真正拉开运维水平的是三个月之后磁盘增长到告警线、某个仓库的元数据索引坏掉、升级时发现没有可用备份。这几件事提前做成本很低。9.1 清理策略和 blob store 压实Nexus 不会自动删东西磁盘只会一直涨。合理做法是三步走在Repository→Cleanup Policies里建策略按最后下载时间或最后更新时间加保留天数来定规则。快照类仓库可以激进一些比如保留 30 天release 仓库基本不用清。建一个Admin - Cleanup unused components任务让它每天或每周跑一次。它删除的是没有任何仓库再引用的 blob不会误删被引用的内容。建一个Admin - Compact blob store任务定期压实 blob store。前一步删掉的数据在 blob store 里只是标记为未引用磁盘并不会立刻释放压实之后才会真正回收。提示压实任务在大仓库上可能跑很久且期间性能会下降建议放在业务低峰期并且别和别的重任务排在同一时段。9.2 备份到底备什么最简单也最可靠的方式是冷备停掉 Nexus把整个数据目录打包再启动。数据目录的路径就是你前面配的-Dkaraf.data默认大概在sonatype-work/nexus3。systemctl stop nexus tar --exclude./tmp --exclude./cache --exclude./log \ -czf /backup/nexus-data-$(date %F).tar.gz -C /data nexus-data systemctl start nexus排除tmp、cache、log是为了控制体积这三个目录都不影响一致性。绝对不要在运行中直接拷贝数据目录尤其是底层数据库文件拷出来大概率是损坏的恢复时你会得到一堆看不懂的索引异常。9.3 一张故障速查表省掉反复翻日志现象优先排查说明页面打不开进程在端口占用、LimitNOFILE、JVM 堆过小导致频繁 GC看nexus-data/log/nexus.log和karaf.log服务健康但客户端 404仓库类型用错往 group 写、路径层级错用浏览器直接访问那个 URL 验证拉取突然变慢缓存未命中正在回源或上游限流第一次慢属正常持续慢要看上游上传大文件失败Nginxclient_max_body_size、超时设置同时检查 Nexus 侧是否有大小限制磁盘满导致服务异常blob store 增长、清理策略未生效先扩容止血再调整保留策略客户端报证书错误自签证书未导入信任链导入 CA别关strict-ssl/gpgcheck健康检查可以直接调接口方便接进监控curl -u monitor:密码 -s https://nexus.internal.example.com/service/rest/v1/status curl -u monitor:密码 -s https://nexus.internal.example.com/service/rest/v1/status/check第二个接口会逐个检查 blob store 的可写性比单纯判断进程存活更有意义建议直接接到告警里。最后分享一个我自己用下来的经验这套环境搭好之后把四种格式的客户端配置都整理成可以一键执行的脚本放进内部文档或者配置管理工具里。新人配环境从折腾半天变成跑一条命令这才是私库真正发挥价值的地方——它不只是让下载变快而是把环境怎么配这件事从每个人的个人经验变成了团队可复制的资产。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门