首页 / 资讯中心 / 文章详情

Nexus 3.24.0-02 私有制品库落地与Maven/NPM缓存避坑

Nexus 3.24.0-02 私有制品库落地与Maven/NPM缓存避坑 ★ FEATURED ARTICLE
简介nexus-3.24.0-02-unix.tar.gz 是 Sonatype Nexus Repository Manager 3.24.0-02 的 Unix/Linux 官方安装包面向 Java 后端、前端 NPM 使用者及需要搭建私服或制品仓库的运维与开发团队解决 Maven、NPM 等依赖集中代理、缓存、私有托管与权限管理问题。压缩包约 149.69MB文件总数与类型明细上游暂未提供解压后主要得到 nexus-3.24.0-02 服务目录和 sonatype-work 运行数据目录分别承载可执行文件、配置、库文件以及制品、索引、日志和数据库内容。已有 212 人浏览学习。它可作为 Nexus 3.24 版本部署与配置的原始安装材料便于读者实践 Maven 代理仓库、NPM 代理与私有仓库、仓库组和权限配置理解 conf/nexus.properties 及服务目录、工作目录分离的目录结构适合搭建内网制品库和排查依赖下载效率问题。1. 私有制品库这件事别再用本地缓存硬扛了前阵子帮一个小组收拾构建环境十来个项目共用一台构建机本地.m2攒到三十多 G还是天天有人抱怨 Maven 拉包卡在 DownloadingNPM 那边和 registry 的连接偶尔直接超时中断CI 一跑就是十几分钟一动不动。这类问题的根子往往不是带宽而是没有本地制品缓存层每次构建都要跟外部仓库重新协商。nexus-3.24.0-02-unix.tar.gz就是能用上的东西——一个解压即跑的仓库管理服务把 Maven 的 jar、NPM 的 tarball 缓到内网团队只认一个地址。这篇讲清三件事这个版本包在 Unix 上怎么落地、Maven 和 NPM 两类仓库怎么规划串联、以及上线后最容易踩的坑。2. 解包与首次启动3.24.0-02 这个 tar.gz 里装了什么2.1 为什么挑 unix tar.gz 而不是镜像或其他包同一个版本常见的分发形态有三类unix 的.tar.gz、容器镜像、Windows 的 zip。三个东西功能上是一套代码差别全在部署边界上。我一般优先选 tar.gz原因很实在目标机器往往在内网没有镜像仓库可用镜像还得先解决传输和导入问题而 tar.gz 就是一个压缩包scp过去解压就能跑。形态前置条件参数调整升级方式适合场景unix tar.gz一台有 JDK 的 Linux一个可写目录直接改bin/nexus.vmoptions换目录、改软链、重启内网离线、单机部署、需要抠内存参数容器镜像有可用的镜像仓库或能导入离线镜像改环境变量或挂载配置换 tag已有编排平台、要求快速重建Windows zipWindows Server JDK改bin\nexus.vmoptions换目录少量遗留的 Windows 构建机选 tar.gz 还有一层3.24.0-02 这个版本号是固定的包一旦落地下次迁移或重建复现的是同一个版本不会因为拉了个latest就莫名多出一堆行为差异。我见过太多“上周还好好的这周就起不来”的事故最后追下去都是镜像 tag 被人覆盖了。需要提前确认一件事这个版本对 JDK 的要求偏保守长期验证过的组合是 JDK 8。机器上如果默认装的是更高的版本别指望它能自动兼容先在测试机上用java -version对一下把JAVA_HOME指到 8 再启动能省掉一轮没有意义的排查。2.2 目录结构、运行用户与 JVM 参数包解开后是两个平级目录一个是程序目录名字带版本号另一个是数据目录默认叫sonatype-work里面nexus3/才是真正的数据根包含 blob 存储、数据库、日志、配置。日常操作里程序目录基本不用碰升级时整个替换掉即可数据目录必须单独保住。第一件事是把目录固定成一个稳定路径别让版本号进到启动脚本里否则以后每次升级都要改一堆配置# 解包到统一父目录程序目录重命名为 current数据目录单独挪出来 sudo mkdir -p /opt/nexus sudo tar -xzf nexus-3.24.0-02-unix.tar.gz -C /opt/nexus sudo mv /opt/nexus/nexus-3.24.0-02 /opt/nexus/current sudo mv /opt/nexus/sonatype-work /opt/nexus/data # 建一个不可登录的服务账号别用 root 跑 sudo useradd -r -s /bin/false nexus sudo chown -R nexus:nexus /opt/nexus这段的关键点有三个。current这个软路径是给 systemd 和运维脚本用的升级时只需要重新指向新目录/opt/nexus/data单独放到一个空间足够的分区因为后面缓存会持续增长跟程序目录混在一起容易把系统盘写满chown必须在启动前做完用 root 启动过一次之后再改属主blob 文件里会残留 root 权限后面再启动就报权限错误属于典型的血泪经验。接着改 JVM 参数。bin/nexus.vmoptions里默认给的是 1200M 堆小团队够用但一旦开了多个 group 仓库、并发构建上来这个值会明显不够# 堆大小按物理内存的 1/4 左右给别超过 8GNexus 不是吃堆型的服务 sudo sed -i s/^-Xms.*/-Xms2703M/ /opt/nexus/current/bin/nexus.vmoptions sudo sed -i s/^-Xmx.*/-Xmx2703M/ /opt/nexus/current/bin/nexus.vmoptions # 数据目录改到 /opt/nexus/data两处都要改 sudo sed -i s#^-Dkaraf.data.*#-Dkaraf.data/opt/nexus/data/nexus3# /opt/nexus/current/bin/nexus.vmoptions sudo sed -i s#^-Dkaraf.log.*#-Dkaraf.log/opt/nexus/data/nexus3/log# /opt/nexus/current/bin/nexus.vmoptions grep -E ^-Xm|^-Dkaraf /opt/nexus/current/bin/nexus.vmoptions-Xms和-Xmx设成一样是为了避免运行期反复扩堆这类服务一旦堆抖动表现就是请求间歇性卡顿很难定位。-Dkaraf.data决定了数据落在哪如果只改了一个不注意改-Dkaraf.log日志还会写到老路径下次出问题查日志查不到等于给自己留了个黑匣子。改完用grep确认一遍比盲信sed稳妥。2.3 启动、端口与初始口令前台先跑一次把启动过程的日志看全别上来就丢后台# 前台启动能看到完整启动日志第一次务必这么跑 sudo -u nexus /opt/nexus/current/bin/nexus run # 观察这行日志说明起来了 # Started Sonatype Nexus OSS 3.24.0-02run是前台模式start是后台模式。第一次排错用run日志直接打到终端确认能起来之后再换成 systemd 托管。默认监听 8081上下文路径是根路径浏览器访问http://机器IP:8081/就是界面。初始管理员口令不在配置文件里而是启动后生成的一个一次性文件# 初始口令文件第一次登录后该文件会被自动删除 sudo cat /opt/nexus/data/nexus3/admin.password # 日志位置起不来看这里 sudo tail -n 200 /opt/nexus/data/nexus3/log/nexus.log用户名是admin密码取上面那个文件的内容。登录后会强制改密码改完这个文件就消失了所以第一次进去之后顺手把新口令记到内部凭据管理里别指望还能再翻出来。如果口令文件不存在而你又没记密码只能走重置流程那就要停机改库很麻烦——这个后悔药不好吃。systemd 单元写起来很短重点是User、LimitNOFILE和重启策略# /etc/systemd/system/nexus.service [Unit] Descriptionnexus repository Afternetwork.target [Service] Typeforking Usernexus LimitNOFILE65536 ExecStart/opt/nexus/current/bin/nexus start ExecStop/opt/nexus/current/bin/nexus stop Restarton-abort [Install] WantedBymulti-user.targetLimitNOFILE必须显式给默认的 1024 在并发拉包时会撞到文件句柄上限报出来的错误是Too many open files看着像磁盘问题其实是句柄问题。Restarton-abort只处理异常退出正常 stop 不会被拉起来避免运维脚本和 systemd 打架。3. 仓库规划Maven 与 NPM 两类格式怎么建、怎么串3.1 hosted、proxy、group 三件套与命名规范Nexus 的核心模型只有三个词理解这三个词整个规划就通了。hosted 是自建的、往里推包的仓库proxy 是代理外部仓库的缓存层group 是把前两者聚合成一个对外地址的门面。客户端永远只认 group 的地址这样内部包和外部包走同一个入口配置不用随仓库增减而变。类型作用Maven 典型命名NPM 典型命名是否对客户端暴露hosted (release)存内部正式构件maven-releasesnpm-hosted否只挂进 grouphosted (snapshot)存内部快照maven-snapshots—否proxy缓存外部仓库maven-centralnpm-proxy否group聚合读写入口maven-publicnpm-group是唯一对外地址命名上我坚持一条规矩类型前缀 来源全部小写中划线。原因是这个仓库名会出现在settings.xml、.npmrc、CI 变量、甚至 Dockerfile 里名字一乱后面 grep 都搜不齐。曾经接手过一套环境同一个人建了maven、Maven-Public、maven_public三个仓库最后没人说得清哪个在用。还有一处细节hosted 的部署策略要分开设。正式包仓库设成Disable Redeploy同一个版本号不允许覆盖逼着大家升版本快照仓库设成Allow Redeploy否则 CI 连推两次就报 400。3.2 Maven 代理仓库的关键参数建maven-central代理仓库时界面上参数不少真正影响使用的就那几个参数建议值说明Remote storageMaven Central 官方地址代理源内网无外网时改成上级仓库地址Auto blocking enabled勾选上游连续失败自动摘除避免拖慢整体响应Auto block timeout1440 分钟摘除后多久重试别设太小Content max age1440 分钟缓存有效期设 -1 表示永久不校验Metadata max age1440 分钟maven-metadata.xml的有效期必须比构件短Artifact max age-1 或 1440 分钟正式版构件一般不需要重复校验Layout policyPermissive宽松模式避免非标准布局的包被拒Checksum policyWarn校验失败只告警不阻断内网代理场景更实用这里最容易翻车的是Metadata max age。有人图省事把所有 max age 全设成 -1结果上游发了新版本本地怎么都刷不出来mvn -U强制更新也没用因为 Nexus 自己认为缓存永远新鲜。快照和元数据这类会变的内容TTL 必须留一个有限值。Checksum policy设成Strict也有代价上游仓库偶尔会有校验文件缺失或格式不规范的构件严格模式直接拒绝构建报错但错误信息指向的是校验和不匹配新手很难联想到是策略问题。内网代理场景我一般用Warn。建完代理后maven-public这个 group 的成员顺序有讲究maven-releases→maven-snapshots→maven-central。内部仓库放前面是为了让同名构件优先命中内部版本如果顺序反了内部修过的包会被中央仓库的旧版盖掉这种问题排查起来极其玄学。3.3 NPM 仓库的 registry 与 scope 规划NPM 侧的模型和 Maven 一样但多一层 scope 的概念规划时要一起考虑。常见做法是建三个npm-proxy代理公共源、npm-hosted存内部包、npm-group聚合前两者。只有三个仓库不够还要决定“内部包用什么 scope”。约定是这样内部包统一用公司缩写/包名的形式scope 直连 hosted其余所有包走 group。这样做的好处是发布路径和拉取路径彻底分开——发布只可能打到 hosted不会误推到 group 上拉取时内部包和公共包又都走一个地址package-lock.json里不会出现两套源。仓库类型用途客户端配置方式npm-proxyproxy缓存公共包不直接配置挂在 group 下npm-hostedhosted内部包发布scope 级 registrynpm-groupgroup统一拉取入口全局 registrygroup 的成员顺序同理npm-hosted放在npm-proxy前面。这样内部包名一旦和公共包重名优先拿内部的避免供应链混淆。另外提醒一句NPM 的 group 仓库里不要放npm-hosted之外的可写成员权限一旦配错匿名用户就能往代理仓库里推包。4. 客户端接入settings.xml 与 .npmrc 抄作业4.1 Mavenmirror、servers 与发布配置Maven 侧要改两个文件全局的settings.xml管镜像和认证项目里的pom.xml管发布地址。先看settings.xmlsettings mirrors !-- 所有 central 请求走内网 group客户端不再直连外部 -- mirror idnexus-public/id nameinternal nexus group/name urlhttp://192.168.10.20:8081/repository/maven-public//url mirrorOfcentral/mirrorOf /mirror /mirrors servers !-- id 必须和 pom 里 distributionManagement 的 id 完全一致 -- server idnexus-releases/id usernamedeployer/username password********/password /server server idnexus-snapshots/id usernamedeployer/username password********/password /server /servers /settingsmirrorOf的取值是最容易出错的地方。写central只劫持中央仓库写*会劫持所有仓库包括项目pom.xml里自定义的那些如果你的项目依赖了另一个团队的私服地址*会把它也指向 Nexus然后 404。稳妥写法是external:*或者用排除法*,!my-other-repo。这个坑我在三个不同团队见过每次都要解释一遍。server的id和pom.xml里的distributionManagement的id必须字面一致差一个字母认证就拿不到报的是 401但错误信息只会说 Unauthorized不会告诉你 id 对不上。发布配置长这样distributionManagement repository idnexus-releases/id urlhttp://192.168.10.20:8081/repository/maven-releases//url /repository snapshotRepository idnexus-snapshots/id urlhttp://192.168.10.20:8081/repository/maven-snapshots//url /snapshotRepository /distributionManagement建议把这段放进公司级的父 POM各子项目继承省得每个项目都复制一遍还复制错。发布账号单独建一个deployer只给 releases 和 snapshots 的写权限别用 admin 发布凭据一旦泄露代价太大。4.2 NPMregistry、scope 与认证NPM 侧改.npmrc项目级或用户级都行推荐项目级放一份模板用户级放凭据# 公共包和内部包统一走 group registryhttp://192.168.10.20:8081/repository/npm-group/ # 内部 scope 直连 hosted发布只可能打到这个仓库 corp:registryhttp://192.168.10.20:8081/repository/npm-hosted/ # 认证按 registry 路径精确匹配末尾斜杠不能少 //192.168.10.20:8081/repository/npm-group/:_auth BASE64编码串 //192.168.10.20:8081/repository/npm-hosted/:_auth BASE64编码串 always-authtrue三个参数说明白。registry是全局默认源所有不带 scope 的包都走这里corp:registry是 scope 级覆盖优先级高于全局发布内部包时自动落到 hosted_auth的 key 必须和 registry 的 URL 前缀逐字符匹配包括协议、端口和末尾斜杠少一个斜杠认证就不生效但 NPM 只会报一个笼统的 401。always-authtrue这个开关在 Nexus 前面挂反向代理时尤其重要不加的话 NPM 只在部分请求上带凭据表现为安装能过、发布 401。认证串的生成方式# 生成 base64 凭据注意 -n 不能少否则会把换行符编进去 printf %s:%s deployer your-password | base64 # 或者直接走交互式登录Nexus 支持 npm token npm login --registryhttp://192.168.10.20:8081/repository/npm-hosted/printf比echo稳echo在不同 shell 下对换行的处理不一致编出来的串末尾多一个字符认证就失败而且肉眼完全看不出来。用npm login的话服务端需要先启用 npm Bearer Token 相关的认证域否则登录会成功但拿不到 token这一步在 Nexus 的认证配置页里勾一下即可。4.3 用一条命令验证链路通不通配置改完不要急着让全组切换先自己验证三件事能不能从 group 拉到包、log 里有没有命中缓存、能不能往 hosted 推包。# Maven拉一个确定存在的构件走临时本地仓库避免污染 mvn -s settings.xml -Dmaven.repo.local/tmp/m2-test \ dependency:get -Dartifactorg.slf4j:slf4j-api:1.7.30 # NPM查版本号能返回说明 registry 通了 npm view lodash version --registryhttp://192.168.10.20:8081/repository/npm-group/ # NPM登录状态自检 npm whoami --registryhttp://192.168.10.20:8081/repository/npm-hosted/-Dmaven.repo.local指定临时目录很关键用默认的~/.m2验证即使 Nexus 挂了也可能因为本地有缓存而误判成功。验证完之后去 Nexus 界面的 Browse 里看maven-central下有没有出现刚拉的那个构件出现了说明缓存生效再tail一下request.log能看到请求是从内网地址进来的还是回源出去的这是判断代理是否真正生效最直接的证据。5. 避坑与排查五个翻车点5.1 前台跑得起systemd 起不来现象手动sudo -u nexus bin/nexus run一切正常换成 systemd 之后状态是 failed日志里只有一行java.lang.IllegalStateException或者干脆为空。原因基本两个一是 systemd 环境里没有继承JAVA_HOME脚本找不到 java二是Typeforking配上start之后主进程 fork 出去systemd 认为进程已经退出。解决在 service 文件里显式加EnvironmentJAVA_HOME/usr/lib/jvm/java-8-openjdk路径用readlink -f $(which java)反推确认Typeforking且ExecStart用的是nexus start而不是run。改完systemctl daemon-reload再启动。5.2 发包报 413 或连接被重置现象npm publish或者mvn deploy传大一点的包时报413 Request Entity Too Large或者直接ECONNRESET。原因Nexus 前面挂了一层反向代理代理的请求体上限是默认的 1M或者读超时太短。直连 8081 没这个问题一经代理就出现。解决代理侧把client_max_body_size调到 0 或 512mproxy_read_timeout调到 300s 以上并且确认proxy_request_buffering的设置不会把大包全缓存在内存里。改完先用curl -X POST传一个大文件对比确认不是 Nexus 自己的限制。5.3 npm publish 一直 401但 login 是成功的现象npm login提示成功npm whoami也能返回用户名但npm publish报 401 或 403。原因分三类_auth的 key 和 registry 路径不精确匹配尤其是末尾斜杠hosted 仓库的部署策略被设成了Read-only账号有读权限但没有目标仓库的写权限。解决把.npmrc里的认证行打印出来逐字符比对在 Nexus 界面确认 hosted 仓库的 Deployment policy 是Allow Redeploy用管理员账号在仓库的权限页确认deployer角色有nx-repository-view-npm-*-add之类的权限。三类原因表现一样只能一条条排先排配置再排权限。5.4 磁盘半年涨了几百 G现象上线时数据目录只有几 G跑几个月变成几百 G磁盘告警。原因Content max age设成了 -1代理缓存只增不减快照仓库没有清理策略每天 CI 推几十个快照blob store 删了包但底层文件没有压实空间不释放。解决把 proxy 仓库的 max age 调回有限值给 snapshots 配清理策略只保留最近 N 天或最近 N 个版本定期跑 blob store 的 compact 任务。三件事缺一件磁盘都会继续涨。5.5 备份只拷了数据目录恢复后起不来现象把数据目录整个 tar 走换机器解压启动报 blob 缺失或者组件状态异常。原因热备时正在写入数据库和 blob 文件不同步或者只拷了 blob 没拷数据库反之亦然。解决要么停机备份要么先跑一次数据库导出任务再拷 blob 目录两次动作之间停止写入。恢复后先做一致性检查再对外提供服务。备份这件事没有捷径验证过一次恢复流程才算真的有备份。6. 长期运维的两个动作备份脚本与清理任务真正让这套东西能长期跑下去的不是配置多漂亮而是两个固定动作能恢复的备份、会自己打扫的清理任务。备份我一般用停机窗口做脚本很简单但每一步都有原因#!/usr/bin/env bash set -euo pipefail DATA_DIR/opt/nexus/data BACKUP_DIR/backup/nexus STAMP$(date %F-%H%M) # 1. 先停服务保证数据库和 blob 一致 systemctl stop nexus # 2. 打包排除日志目录日志没必要进备份 tar czf ${BACKUP_DIR}/nexus-${STAMP}.tar.gz \ -C $(dirname $DATA_DIR) \ --excludenexus3/log \ $(basename $DATA_DIR) # 3. 起服务无论打包成功与否 systemctl start nexus # 4. 只保留最近 7 份避免备份盘被自己撑满 ls -1t ${BACKUP_DIR}/nexus-*.tar.gz | tail -n 8 | xargs -r rm -f--exclude排除日志是必须的日志目录往往比数据目录还大备份进去纯属浪费空间。tail -n 8配合ls -1t是按时间倒序保留 7 份xargs -r在没匹配到文件时不会报错。set -euo pipefail保证任何一步失败立即退出不会出现“备份文件生成了但内容不完整”这种情况。清理和压实通过 REST 接口触发方便放进定时任务# 触发 blob store 压实回收已删除包占用的磁盘 curl -sS -u admin:密码 -X POST \ http://192.168.10.20:8081/service/rest/v1/tasks \ -H Content-Type: application/json \ -d { name: compact-blob, type: blobstore.compact, enabled: true, alertEmail: , notificationCondition: FAILURE, properties: { blobstoreName: default } } # 查任务状态看 lastRunResult 是不是 OK curl -sS -u admin:密码 \ http://192.168.10.20:8081/service/rest/v1/tasks | head -c 2000type必须是接口文档里列出的类型名写错了会返回 400 但不会告诉你正确的有哪些properties里的blobstoreName要和界面里建的那个名字一模一样。这个任务不要在业务高峰跑压实期间 IO 会明显上来我一般放在凌晨。清理策略本身则在仓库的 Cleanup 配置里设比如快照只保留最近 30 天配合上面的压实任务磁盘占用才会真正降下来。从那以后我每次交付这套东西都会在交付清单里加上一条硬性要求备份恢复必须真跑一遍从备份包里解出来起一个实例登录进去随便拉一个包确认能拉通才算完。没验证过的备份就是心理安慰真出事的时候它不会给你第二次机会。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站