简介:Nexus Repository Manager 3.24.0-02 的 Unix/Linux 安装包,面向使用 Maven、NPM 等构建工具的 Java 与前端开发团队,用于搭建私有软件仓库,集中代理、缓存和分发依赖,缓解公网仓库访问慢、依赖来源分散的问题。压缩包为 gz 格式,体积约 149.69MB,包内文件总数与类型明细未随资源提供;解压后包含服务程序目录与 sonatype-work 运行时目录,前者汇集可执行文件、配置文件和依赖库,后者存放制品、索引、日志及数据库内容,目录职责清晰,便于部署和升级。其 Maven 代理与 NPM 缓存能力可减少对公共仓库的直接访问,已有 212 人学习下载,适合需要内网统一管理依赖的开发者参考。资源可用于规划代理仓库、存储库组和权限配置,也能帮助理解 Nexus 的目录结构与数据持久化方式,为团队依赖治理提供较完整的实践基础。
1. 一个 tar.gz 解压后,落到你手上的是整条依赖链的入口
nexus-3.24.0-02-unix.tar.gz拆开看只有三件事:产品、版本、平台。Nexus Repository Manager 3 的 Unix 发行包,3.24.0-02 是构建号,解压即用,不用编译,也不用先装数据库或容器运行时。它解决的问题很具体:内网机器连不上公共仓库、一条流水线每次构建都要重新下载几百兆依赖、构建产物发出去以后没地方存、三五个团队各自缓存一份还版本对不上。这套东西就是把中央仓库“搬”到内网,再把你自己的产物也放进去,让 Maven、npm、Docker 和一堆杂七杂八的包都从同一个地址取。适合自建构建环境的团队:负责构建和运维的后端、需要给离线环境供包的工程师,以及被反复询问“为什么拉不下来”的人。不适合单机个人项目,因为多出来的部署和维护成本,比省下的那点带宽更贵。
2. 从解压到能登录:nexus-3.24.0-02 起服务的完整路径
2.1 安装目录和 sonatype-work 必须物理分开
tar 包解开以后一般会得到两个并列目录:nexus-3.24.0-02/是程序本体,包含bin、etc、lib、public,里面一行数据都没有,是可以随时替换的;sonatype-work/是数据目录,包含 blob 存储、元数据库、日志、临时文件和首次启动生成的初始密码。很多人图省事把两个目录放在同一块盘上的同一个父目录,结果升级时手一抖把数据一起删了,或者备份脚本把几百 G 的 blob 和几十 M 的程序一起打包,备份窗口越来越长。
正确的做法是让它们落在不同位置,至少不同目录层级,有条件就不同挂载点。程序目录可以随时重装,数据目录则是唯一不可再生资源。
# 上传目录并解压到临时位置 tar -xzf nexus-3.24.0-02-unix.tar.gz -C /tmp # 程序放 /opt,数据放大盘 /data mv /tmp/nexus-3.24.0-02 /opt/nexus mkdir -p /data mv /tmp/sonatype-work /data/sonatype-work # 关键:让程序从 /opt/nexus 启动时,仍然指向 /data 下的数据目录 # 有两种做法,见下文代码本身没什么难度,真正要交代的是最后一步:程序默认会去“自己上一级目录”找sonatype-work。把数据挪到/data之后,要么在启动脚本里改-Dkaraf.data指向,要么更省事——让/opt/nexus/../sonatype-work这个相对路径成立,比如把sonatype-work软链到/data/sonatype-work。
# 做法二:软链,最省心,升级时只换 /opt/nexus,软链不动 ln -s /data/sonatype-work /opt/sonatype-work ls -l /opt/sonatype-work # 确认指向 /data/sonatype-work du -sh /data/sonatype-work # 首次启动前应该是 KB 级别软链的好处是升级路径完全不动,坏处是有人后来把软链改成真实目录就会踩坑,所以建议在目录里放一个 README 写清楚。这一步做完,安装目录和数据目录才真正解耦,后面无论是换机器还是升级版本,都只需要搬其中一半。
2.2 nexus.vmoptions 里的三行内存参数决定它能撑多久
Nexus 3 是 Java 应用,这一代版本线通常以 Java 8 为基线,装 Java 11 或更高版本很可能在启动阶段就报类加载或模块相关的错。这不是玄学,是很多人第一次翻车的地方:装完 JDK 顺手java -version看到 11,然后启动日志停在半路。建议的做法是单独准备一份 JDK 8,在bin/nexus.rc里写INSTALL4J_JAVA_HOME或者直接设置JAVA_HOME,让启动脚本只认这一份。
内存参数在etc/nexus.vmoptions里,常见的三段是初始堆、最大堆和直接内存:
# /opt/nexus/etc/nexus.vmoptions 里最需要动的三行 -Xms2703m -Xmx2703m -XX:MaxDirectMemorySize=2703m # 顺带确认文件描述符,这决定了并发下载会不会被内核挡住 ulimit -n # 小于 65536 就要在 systemd 或 limits.conf 里放开参数怎么定:-Xmx和-XX:MaxDirectMemorySize设成同一个值,这是 Nexus 自身推荐的做法,因为它在代理下载时大量使用堆外缓冲,直接内存给小了会在高并发时抛OutOfMemoryError: Direct buffer memory,堆给小了则会频繁 GC 到 UI 都点不动。生产环境常见起点是 4G 到 8G,仓库体积超过几百 G 或者并发构建机超过二十台,就往上加。但别超过物理内存的一半,否则系统层 OOM killer 会在你不注意的时候把进程干掉,日志里什么都不会留,这是最难查的一类“莫名停了”。
bin/nexus.rc里还有一行run_as_user,建议创建一个专用账号来跑,不要用 root。用 root 跑过一次之后再改回普通账号,数据目录下会留下一堆 root 属主的文件,nexus start会因为写不了日志直接失败。
# 用专用账号启动的典型配置 useradd -r -s /sbin/nologin nexus chown -R nexus:nexus /opt/nexus /data/sonatype-work echo 'run_as_user="nexus"' >> /opt/nexus/bin/nexus.rc2.3 首次启动、取初始密码、马上要做的一件事
启动有两种方式:bin/nexus run是前台运行,日志直接打在终端上,适合首次启动和排错;bin/nexus start是后台运行,日志写到数据目录下的log/nexus.log。首启一定要用run,因为它在初始化元数据库、创建 blob 目录,任何一步失败你都能在屏幕上看到原因。
# 首次启动,前台,别走开 /opt/nexus/bin/nexus run # 另开一个终端看状态,200 就说明服务起来了 curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8081/service/rest/v1/status # 初始密码文件,首次登录后这个文件会被删除 cat /data/sonatype-work/nexus3/admin.passwordcurl返回 200 只是说明 REST 起来了,UI 可能还要再等十几秒。浏览器打开http://<ip>:8081,用admin加文件里的密码登录。
登录后第一件事不是建仓库,而是改密码并删掉admin.password,然后创建一个日常使用的账号,把admin收起来只在必要时用。很多人跳过这步,结果初始密码文件一直躺在磁盘上,任何能读那个目录的人都能拿到最高权限。同时建议顺手把匿名访问的权限确认一遍,默认匿名可以读,如果你不希望未认证用户看到仓库列表,就要在 Security 里关掉——但注意关早了会把后面配 Maven 的人卡住,先用匿名跑通再收紧,顺序别反。
3. proxy、hosted、group:三类仓库怎么排布才不用返工
3.1 三种角色的职责和依赖方向
仓库类型不是可选项,而是有依赖关系的三层结构,命名一旦定下来,后面改一次要通知所有构建机,所以第一次就排清楚。
| 角色 | 作用 | 是否有上游 | 典型命名 |
|---|---|---|---|
| proxy | 代理外部仓库,缓存下载过的包 | 有,指向公共仓库地址 | maven-central、npm-proxy |
| hosted | 存放自己发布或上传的产物 | 无 | maven-releases、maven-snapshots |
| group | 把多个仓库聚合成一个对外地址 | 无,成员是其他仓库 | maven-public |
依赖方向是:group 的成员只能是已存在的 proxy 或 hosted,所以必须先建 proxy 和 hosted,最后建 group。反过来做,建 group 时下拉框是空的,只能先跳过,回头再编辑,一来一回容易漏掉成员。这条顺序是我被问过最多的问题,血泪经验就是先画好这张表再动手。
maven-releases和maven-snapshots一定要分开,因为版本策略不同:releases 用RELEASE策略,同一个版本号只能发一次,重复发布会返回 400;snapshots 用SNAPSHOT策略,允许覆盖。有人图省事合在一个 hosted 里,结果某天一个正式版本被覆盖,线上依赖被静默改变,就是很难复现的事故。
3.2 用 REST 接口批量建仓库,别在界面上一个个点
界面点击适合第一次理解概念,真部署时建议走 REST。创建 Maven 代理仓库:
NEXUS=http://127.0.0.1:8081 AUTH='admin:你的新密码' curl -u "$AUTH" -X POST "$NEXUS/service/rest/v1/repositories/maven/proxy" \ -H 'Content-Type: application/json' -d '{ "name": "maven-central", "online": true, "storage": { "blobStoreName": "default", "strictContentTypeValidation": true }, "proxy": { "remoteUrl": "https://repo1.maven.org/maven2/", "contentMaxAge": 1440, "metadataMaxAge": 1440 }, "negativeCache": { "enabled": true, "timeToLive": 1440 }, "httpClient": { "blocked": false, "autoBlock": true }, "maven": { "versionPolicy": "RELEASE", "layoutPolicy": "STRICT", "contentDisposition": "ATTACHMENT" } }'逐项说参数。remoteUrl指向上游仓库根地址,末尾要不要斜杠取决于上游,写错会得到 404 而不是配置错误,很难看出来。contentMaxAge是已缓存构件的有效期(分钟),metadataMaxAge只影响maven-metadata.xml这类索引文件,取 1440 表示一天内不重复回源,这个值调大能明显减少外网请求,但会让新发布的版本晚一天被发现,团队做频繁发布时降到 60 更合适。autoBlock打开后,上游连续失败会自动把仓库标记为不可用,避免每次构建都卡在超时上,这是个容易被忽略但很有用的开关。
hosted 和 group 的创建方式一致,只是路径换成/maven/hosted和/maven/group,group 的请求体里用group.memberNames列出成员,顺序有讲究:把 hosted 放前面,代理放后面,这样同名构件优先命中本地发布版本。npm 仓库同理,路径是/service/rest/v1/repositories/npm/proxy,remoteUrl填https://registry.npmjs.org。
建完记得验证,不要只看界面有没有绿点:
# 列出所有仓库,确认名字和格式 curl -s -u "$AUTH" "$NEXUS/service/rest/v1/repositories" | grep '"name"' # 通过 group 实际拉一个构件,这才是最终用户路径 curl -s -o /dev/null -w '%{http_code}\n' \ "$NEXUS/repository/maven-public/junit/junit/4.13.2/junit-4.13.2.pom"第二个命令返回 200 才算通。如果返回 404,先直接打 proxy 仓库的地址确认上游能通,再查 group 的成员列表——group 里没加这个 proxy 是最常见的原因。
3.3 客户端侧:settings.xml 和 .npmrc 的镜像写法
服务端建好只是解决了一半问题,构建机怎么指向它,决定了要不要在每个项目里改配置。
<!-- ~/.m2/settings.xml,用一个 mirror 接管全部请求 --> <settings> <mirrors> <mirror> <id>nexus</id> <name>internal nexus</name> <url>http://10.0.0.10:8081/repository/maven-public/</url> <mirrorOf>*</mirrorOf> </mirror> </mirrors> <servers> <!-- 发布用,id 要和项目 pom 里 distributionManagement 的 id 一致 --> <server> <id>nexus-releases</id> <username>deployer</username> <password>******</password> </server> </servers> </settings>mirrorOf写*表示所有仓库请求都走 Nexus,这是内网环境最常见的做法,代价是项目里额外声明的第三方仓库也会被劫持,如果某个依赖只存在于小众仓库,就会拉不到。遇到这种情况,把它改成*,!custom-repo放行特定 id,比改全局配置更安全。
npm 侧只需要一行:
npm config set registry http://10.0.0.10:8081/repository/npm-group/ npm config set //10.0.0.10:8081/repository/npm-group/:_authToken=<token>token 在 Nexus 的用户设置里生成,密码登录在较新版本里对 npm 不友好。写进项目根的.npmrc更稳,这样换机器不用重新配。
4. 起不来、拉不动、磁盘满:五个现场排查记录
4.1 启动几分钟后进程消失,日志没有任何错误
现象:nexus run跑了半分钟,终端直接回到提示符,nexus.log结尾没有任何异常栈。原因通常是系统层 OOM killer 把进程杀了,因为-Xmx加直接内存超过了物理内存,或者容器有 cgroup 限制但 JVM 没识别。解决:先dmesg | tail看有没有Killed process,有就把nexus.vmoptions里的三行降到物理内存的一半以内;容器里跑还要确认 JVM 用的是容器感知的内存参数,否则它会按宿主机内存来算堆大小。
4.2 8081 端口通,但页面 404 或静态资源全挂
现象:curl状态接口返回 200,浏览器打开却是空白或 404。原因多半是改过etc/nexus-default.properties里的nexus-context-path,或者前面挂了一层反向代理,路径没对齐。解决:确认application-port和nexus-context-path,如果前面有代理,proxy_pass末尾不要吃掉路径,并且要透传Host和X-Forwarded-Proto,否则登录后的跳转会指回错误地址。改完必须重启,这个配置不支持热加载。
4.3 mvn 拉包返回 401 或 403
现象:浏览器能匿名浏览,构建机却拉不下来。原因有三个高频:一是匿名访问被关了但settings.xml里没配server凭据;二是账号有读权限但没有目标仓库的nx-repository-view-*-*-read权限;三是密码里有特殊字符,在 shell 里被转义吃掉。解决:先用curl -u user:pass直接打仓库路径,能通说明是权限之外的问题;再检查角色绑定的是仓库级权限还是全局权限,前者更安全。密码含特殊字符时用单引号或写进文件,别直接拼在命令行里。
4.4 docker push 报 unauthorized 或 405
现象:docker login成功,push 时被拒。原因通常是没有启用 Docker Bearer Token 这个安全域,或者 hosted 仓库的 connector 端口没配。解决:先在 Security 的 Realms 里把 Docker 相关域激活并放到合适位置,再确认仓库配置里httpPort填了一个未被占用的端口(比如 8082),客户端推的是host:8082/repo-name,不是 8081。另外内网 http 端口要在 Docker 的 insecure-registries 里登记,否则会被客户端直接拒绝,这一步跟 Nexus 本身无关,很多人查错方向。
4.5 磁盘涨得比预期快,删了包也不见降
现象:删掉一批构件,df没有任何变化。原因是 blob 存储是追加写,删除只标记元数据,空间要等压缩任务才真正释放。解决:建一个 cleanup policy 挂到仓库上,按“多久没被下载”定期清理;再建一个Admin - Compact blob store类型的任务,每周跑一次。两个任务缺一不可,只清不压缩等于没清。另外别把sonatype-work下的log忘了,访问日志增长速度经常超过构件本身。
5. 备份、迁移与容量水位:把 sonatype-work 安全搬走
5.1 停机备份的最小集合和顺序
备份这件事最怕的是“看起来备了”。热备份直接tar一个正在运行的数据目录,元数据库可能处于不一致状态,恢复时索引和 blob 对不上,表现是仓库列表在但点进去 404。可靠做法是短暂停机:先nexus stop,确认进程退出,再打包。
# 停服务,确认没有残留进程 /opt/nexus/bin/nexus stop sleep 10 ps -ef | grep -c '[n]exus' # 应该是 0 # 备份:先元数据和配置,再 blob,分开打包便于单独恢复 tar -czf /backup/nexus-meta-$(date +%F).tar.gz \ -C /data/sonatype-work nexus3/etc nexus3/db tar -czf /backup/nexus-blobs-$(date +%F).tar.gz \ -C /data/sonatype-work nexus3/blobs分开打包的理由:元数据只有几十兆,可以每天备;blob 动辄几百 G,按周增量更现实。恢复时先解元数据再解 blob,顺序反了首次启动会重建索引,慢且可能丢内容。备份文件本身要放到另一台机器或对象存储上,同盘备份在这类场景里等于没备。
5.2 换机器迁移:路径、权限、UID 三处对齐
迁移失败基本都不是技术问题,而是 UID 和路径没对齐。旧机器上跑服务的账号是 998,新机器上useradd出来是 1001,文件搬过去属主全变成数字,服务起不来,日志里写的是权限拒绝。
# 新机器上先建同名账号并确认 UID id nexus # 用 rsync 保权限,-a 保留属主属组,-S 处理稀疏文件,blob 里有很多 rsync -aSP --delete /data/sonatype-work/ newhost:/data/sonatype-work/ # 搬完核对属主,全量刷一遍比逐个查快 chown -R nexus:nexus /data/sonatype-work如果两台机器 UID 确实无法一致,就在 rsync 之后统一chown,别指望 rsync 能跨 UID 保属主。路径也要一致:新机器上如果程序装在别的位置,软链关系要重建,否则启动时找不到sonatype-work,它会默默新建一个空目录,服务起来了但仓库全是空的——这个现象非常吓人,其实就是路径没对上。
迁移完成后先别急着切流量,用curl打几个已知构件的路径,比对返回的Content-Length,一致再改 DNS 或配置。
5.3 磁盘水位:三个任务决定半年后要不要扩容
| 任务 | 作用 | 建议频率 |
|---|---|---|
| Cleanup service | 按策略删除长期未下载的构件 | 每天 |
| Compact blob store | 真正释放已删除数据占用的块 | 每周 |
| 日志轮转 | 控制访问日志和 JVM 日志增长 | 系统层配 |
除了任务,还要给自己留一条提前告警线。我一般会在容量到 70% 时就开始规划扩容,而不是等到 90%,因为清理和压缩本身也需要临时空间,磁盘写满时连元数据库都可能损坏。Nexus 的 blob 增长不是线性的,一次大规模发布或者引入一个新的 Docker 基础镜像,可能就是几十 G 的跳变。
6. 放进流水线之后,我固定盯的三个信号
部署完成不等于结束,真正决定这套东西能不能长期用的,是你有没有在它出问题时第一时间知道。我在把 Nexus 接进流水线之后固定看三样东西,都是很便宜就能拿到的信号。
第一个是仓库的响应耗时。不查业务接口,只打一个固定构件的路径,每秒一次,超过 2 秒就告警。这个指标能在磁盘满、GC 抖动、上游不通之前就给出提示,比看进程存活有用得多。
# 一个最小的探测脚本,丢进 cron 即可 CODE=$(curl -s -o /dev/null -w '%{http_code} %{time_total}' \ http://10.0.0.10:8081/repository/maven-public/junit/junit/4.13.2/junit-4.13.2.pom) echo "$(date +%F_%T) $CODE" >> /var/log/nexus-probe.log第二个是失败率而不是总量。Nexus 的访问日志里 404 和 503 的比例更值得看:404 高了说明有项目在请求不存在的构件,通常是版本号写错或者 group 里漏了成员;503 高了说明上游不稳或者autoBlock触发了。按小时聚合一下,趋势比单点更有意义。
第三个是磁盘增速。每天记录一次du -sh /data/sonatype-work/blobs,算七天移动平均,能提前两三周预判扩容时间。这个数字我一般写进值班看板,比任何监控系统的默认指标都直观。
最后说一个我自己踩过的坑:早期为了省事,把 Nexus 和构建机放在同一台机器上,构建高峰时 JVM 抢 CPU,仓库响应变慢,然后构建超时重试,重试又加重负载,形成正反馈。后来把两者拆开,问题自然消失。制品仓库是基础设施,它的稳定性不该被业务负载绑架。这套东西值不值得做,取决于你们是否有三个人以上、三台构建机以上的规模,到这个量级,自建的收益就很明显了。希望帮到你。
本文还有配套的精品资源,点击获取