☰
Nexus 2.11.4迁移升级至3.12.0:Maven私库实战
2026/10/2 15:57:31 网站建设 项目流程

手上这套 Nexus 2.11.4 跑了几年,里面塞满了 maven 私库的各种 Releases、Snapshots、第三方包和代理缓存,一直没人敢碰。直到 JDK 升级、磁盘告警、新项目要 npm 和 docker 镜像源,才发现继续留着它的成本已经比迁移更高。这篇文章就是我把一套线上运行多年的 maven 私库从 Nexus 2.11.4 迁移升级到 Nexus 3.12.0 的全过程记录,包括路线选型、容量估算、升级代理的实际用法、脚本兜底方案、客户端 settings.xml 的改动点,以及中途踩到的各种坑。适合手上有老 Nexus 2 环境、又必须往前走一步的运维和中间件同学,也适合刚接手私库、还在搞清楚 maven 仓库是怎么一回事的人。我不会只讲"点几下就完成了",重点讲每一步为什么这么做,以及哪些地方一旦做错就得重来。

1. 迁移这件事的整体判断与路线选型

1.1 2.11.4 到底卡在哪里,为什么非动不可

Nexus 2.11.4 是 Nexus 2 系列的末期版本,本身稳定性没什么大问题,真正让人难受的是它背后的生态已经停更。它只能管 Maven 这一类仓库格式,想给前端团队开一个 npm 私库、给容器团队开一个 docker registry,就得再装一套别的服务,账号体系、权限模型、备份策略全部割裂。而我们这边的实际需求很直接:前端的 node_modules 想走内网、镜像构建想从内网拉基础镜像、Java 那边的老依赖又必须保留,三个需求叠在一起,Nexus 2 完全没有办法承接。

另一个绕不开的点是 Java 运行时。Nexus 2 的部署环境是 JDK 7/8 时代的产物,随着服务器统一往更高版本的 JDK 走,旧进程的兼容性开始变成隐患。再加上 Nexus 2 的搜索和浏览界面在老浏览器上表现越来越差,新人接手时连"这个依赖到底在哪个仓库"都要翻半天。这些问题单看都不致命,堆在一起就变成一个结论:与其继续给老系统打补丁,不如一次性换到 Nexus 3,把 Maven、npm、docker 都收进同一个实例里管。

注意:迁移是单向的。Nexus 3 没有官方的"降级回 Nexus 2"通道,所以真正动手之前,Nexus 2 的数据目录必须有一份可用的冷备份,这不是可选项。

1.2 三条迁移路线:原地升级、并行部署、纯脚本搬运

我一开始把可能的路径全部列了出来,对比之后才决定走哪条。

路线做法优点风险与代价
原地升级在旧机器上把 Nexus 3 装到新目录,复用同一份数据省机器Nexus 2 与 Nexus 3 的数据结构完全不同,实际上做不到"复用",此路基本不通
并行部署新机器装 Nexus 3,通过升级代理从旧实例拉数据旧库不动、可回滚、有官方工具需要双份磁盘、迁移窗口内要冻结写入
纯脚本搬运直接读 Nexus 2 的存储目录,用 REST 或 deploy 回灌不依赖官方工具、可控粒度慢、元数据容易丢、快照处理麻烦

"原地升级"这条我很快就否掉了。Nexus 2 的存储是纯粹的文件树加上本地索引,Nexus 3 换成了一套完全不同的元数据数据库加上分桶式的 blob store,两者之间不存在版本覆盖式的升级关系。想省机器的人往往在这里踩坑:把 Nexus 3 装到 Nexus 2 的目录里,启动之后发现仓库列表是空的,甚至把原来能用的旧实例搞坏。

所以我走的是并行部署,用新机器承接,旧实例保持只读,等到验证没问题再下线。这条路的代价是要多准备一台机器和一份磁盘空间,但换来的是随时可以退回旧地址的能力——在私库这种"一挂全公司都构建不了"的场景里,这个退路值这个钱。脚本搬运我没有放弃,而是作为兜底方案准备着,后面第 5 节会讲它的具体写法,因为实际迁移时确实有几个仓库是官方工具搞不定、只能自己搬的。

1.3 为什么落在 3.12.0 这个版本上

版本选择上我没有追最新,而是选了 3.12.0,理由有三个。第一,这个版本对 Maven 2 迁移的支持已经相对成熟,升级代理的流程在这个阶段已经跑通,社区里能查到的案例也最多。第二,3.12.0 对 JDK 的要求就是 JDK 8,跟我们现有的服务器基线完全对得上,不需要为了一个私库去动整个 JDK 版本策略。第三,再往后的版本会引入一些新的管理概念,配置项和界面都变了,团队里其他人上手成本会变高。

版本这件事上我的建议是:不要选太新的,也不要停在最早的 3.0.x。3.0.x 的迁移工具在早期确实有过一批已知问题,比如大仓库迁移中途断掉之后不好恢复;而太新的版本你又得重新踩一遍别人没踩过的坑。3.12.0 属于中间那段"该修的都修了、文档也齐了"的区间,对一次性的迁移任务来说是最合适的选择。

2. 动手前的资产盘点与容量估算

2.1 先把 Nexus 2 的仓库家底摸清楚

迁移最容易出事的地方不是工具用错,而是压根不知道自己有什么。我做的第一件事是登录 Nexus 2,把 Repositories 页面里所有仓库列出来,逐个记录类型、格式、是否被 group 引用。Nexus 2 里常见的仓库大致是这几类:托管型,比如团队自己 deploy 的 releases 和 snapshots,还有手工上传的第三方包;代理型,比如指向中央仓库的代理和指向阿里云镜像的代理;虚拟型,也就是把上面这些聚合起来对外提供统一地址的 group。

这一步的意义在于决定迁移顺序。我的策略是先迁代理型仓库,再迁托管型的,最后处理 group。原因很直接:代理型仓库里的大量内容其实是缓存,即使丢了也能重新从上游拉回来,就算迁移失败影响也可控;而托管型仓库里是团队自己发布的包,很多老版本的上游根本找不回来,一旦丢失就是永久损失,必须放在网络和磁盘都验证稳定之后再动。

盘点的时候还要顺手记下每个仓库的体积。在 Nexus 2 的存储目录下用du -sh逐个统计,比在界面上看更准:

cd /data/nexus/sonatype-work/nexus/storage du -sh */ | sort -h

跑完这条命令你会看到 releases、snapshots、thirdparty、central 这些目录各自占了多少。我这边光是中央仓库的代理缓存就有将近 90G,团队自己发布的 releases 反而只有 30G 出头,这个分布直接决定了我后面磁盘要怎么规划。

2.2 磁盘和内存的账要提前算

磁盘这块必须留足冗余,因为迁移期间 Nexus 2 和 Nexus 3 是同时存在的,两边的数据是双份。Nexus 3 的 blob store 除了内容本身,还会有一套元数据数据库和索引文件,实际占用通常会比原库略高一点。我的经验公式是:新机器可用磁盘 ≥ 原库体积 × 1.5,如果是那种代理仓库特别大的场景,直接按 2 倍准备更稳妥。

内存的账要算得更细一些。Nexus 3 是 JVM 应用,堆内存之外还用了直接内存做文件传输的缓冲,所以不能只看-Xmx。物理内存的分配思路是:JVM 堆占三分之一到二分之一,剩下的留给操作系统做文件缓存和直接内存。具体取值可以参考下面这张表,是我在几个不同体量的环境上验证过的范围。

数据总量建议 -Xms/-Xmx建议 MaxDirectMemorySize物理内存起点
100G 以内4g4g8G
100G 到 500G8g8g16G
500G 以上16g16g32G

提示:堆内存不是越大越好。把-Xmx设到物理内存的 80% 以上,剩下的内存不够做文件缓存,反而会让大批量拉取依赖时的响应变慢,甚至触发系统的内存回收导致进程假死。

2.3 账号、权限、定时任务清单

除了仓库内容,还有三类"软资产"容易在迁移时被忽略。第一类是用户和角色。Nexus 2 里的用户如果只在本地库存在,迁移工具是不会帮你带过去的,需要在 Nexus 3 里重建,或者干脆接入统一认证,一次性解决。

第二类是权限模型。Nexus 3 的权限粒度比 Nexus 2 细,而且默认的匿名访问策略更严格。我在盘点时就明确了哪些仓库允许匿名读、哪些必须认证,这个结论会直接影响迁移后客户端是否需要配置账号,也决定第 6 节的 settings.xml 要怎么写。

第三类是定时任务和清理策略。Nexus 2 里通常配了快照清理、索引重建这类计划任务,这些任务的定义不会被迁移带过去,需要在 Nexus 3 里重新配。别小看这一步,我见过迁移完之后没人管快照清理,半年后磁盘就满了。

3. Nexus 3.12.0 的环境准备与落地部署

3.1 JDK 与操作系统的前置条件

Nexus 3.12.0 跑在 JDK 8 上最稳,这一点没什么可商量的。我第一次试的时候用了更新的 JDK 版本,启动脚本直接报错退出,日志里是模块相关的异常——因为那个阶段的 Nexus 还没有适配新版本 JDK 的模块系统。所以环境准备阶段就把 JDK 8 装上,并且用JAVA_HOME明确指出来,不要让系统 PATH 里先撞到别的版本。

export JAVA_HOME=/usr/local/jdk1.8.0_xxx export PATH=$JAVA_HOME/bin:$PATH java -version

除了 JDK,还有两个系统层面的参数要看:文件句柄数和最大进程数。Nexus 3 在迁移大批量小文件时会同时打开很多句柄,默认的 1024 很容易不够用。我在/etc/security/limits.conf里给运行 Nexus 的账号加了nofile 65536,这个改动很小,但能避免迁移到一半突然出现一堆莫名其妙的 IO 异常。

3.2 安装包部署与目录规划

安装包从官方渠道下载后解压到一个独立目录,比如/opt/nexus-3.12.0-01,然后用软链接/opt/nexus指过去,方便后面升级时切换。数据目录不要放在安装目录里面,这是我吃过亏的地方:早期有人图省事把数据放在安装目录,结果换版本时顺手把整个目录删了重建,数据一起没了。

目录规划我按这个结构走:安装目录放程序,数据目录单独挂一块盘放sonatype-work,日志通过配置输出到一块独立的、不那么重要的盘上。这样做的好处是备份目标非常清晰,只需要备份数据目录,程序目录随时可以重新解压一份出来。

tar -zxf nexus-3.12.0-01-unix.tar.gz -C /opt/ ln -s /opt/nexus-3.12.0-01 /opt/nexus mkdir -p /data/nexus-data chown -R nexus:nexus /opt/nexus-3.12.0-01 /data/nexus-data

数据目录的位置通过bin/nexus.vmoptions和etc/nexus-default.properties调整,改完之后用bin/nexus run前台启动一次,看看日志里输出的数据目录是不是你规划的那个,确认之后再改成后台服务方式运行。

3.3 首次启动与管理员账号

3.12.0 这个版本第一次启动后,管理员账号还是传统的默认凭据,登录后会强制要求改密码。改成强密码之后立刻做两件事:一是把匿名访问的策略确认一遍,二是配置一个独立的部署账号给 CI 用。用管理员账号跑 CI 是很多团队的习惯,但一旦这个账号的密码轮换,所有流水线全挂,这个坑完全可以避免。

匿名访问这块我的建议是:私库里的托管仓库一律不允许匿名写,读权限按团队实际情况决定。如果允许匿名读,客户端就不用配凭据,接入成本低,但等于内网的任何人都能下载你的私有包。我们最终选择了对外的 group 开放匿名读、托管仓库本身禁止匿名,这个折中方案在便利性和隔离性之间相对平衡。

3.4 用 Docker 先搭一套演练环境

正式迁移之前,我先用容器起了一套临时环境做演练,把整个流程跑通一遍,确认每一步的耗时和可能失败的位置。这一步的价值在于:正式迁移的时间窗口是有限的,如果第一次操作就上生产,遇到问题只能现场摸索,而演练环境里你可以随便重启、随便重来。

演练环境要注意的是持久化目录的挂载,容器一删数据就没,所以数据目录必须挂出来。另外端口映射要跟正式环境保持一致,因为后面配置升级代理的连接地址时,端口不同会让脚本没法直接复用。演练完之后,这套脚本和命令基本可以原样搬到正式环境,效率提升非常明显。

4. 核心迁移流程:升级代理的实际用法

4.1 2.11.4 到 2.14.x 的这一跳不能省

这是整个迁移里最关键、也最容易让人卡住的一点。官方的升级代理对 Nexus 2 的版本是有下限要求的,2.11.4 这个版本太低,代理直接连不上或者读不出数据。所以正式迁移的第一步,是在旧机器上把 Nexus 2 从 2.11.4 升到 2 系列的末期版本(2.14.x 这个区间),这一步是原地覆盖式的版本升级,相对安全,但依然要先做冷备份。

做这一跳之前我的建议是:把 Nexus 2 的整个数据目录先tar一份到别的盘上,然后停服务、替换程序目录、启动。升级完之后重点验证三件事:仓库列表是否完整、随机挑几个坐标能不能正常下载、管理界面登录是否正常。三件事都过了,再进入下一步。

注意:Nexus 2 的版本升级只替换程序目录,不要动数据目录。把数据目录也一起替换或者覆盖,等同于把仓库内容全部清空。

4.2 升级代理的部署与连通性检查

升级代理是一个独立的小程序,部署在与 Nexus 2 网络可达的机器上,它负责把 Nexus 2 的数据以标准接口的形式暴露给 Nexus 3。部署逻辑很简单:解压、配置指向 Nexus 2 的地址和管理员凭据、启动,然后它会监听一个自己的端口(默认在 8070 附近,具体以你下载版本的说明为准)。

这里有几个连通性检查必须做。第一,从 Nexus 3 所在机器curl升级代理的端口,确认能通。第二,确认代理配置里填的 Nexus 2 管理员账号确实有读取所有仓库的权限,否则迁移会表现为"只迁了一部分,剩下的没报错但也没数据"。第三,检查两边的防火墙策略,尤其是跨网段的场景,端口放行经常漏掉。

还有一件事必须提前做:冻结 Nexus 2 的写入。迁移过程中如果有新的依赖被 deploy 到旧库,这部分数据是不会被同步过去的。最稳妥的做法是临时收回部署权限,让 CI 的发布任务失败一段时间,等迁移验证完成后再把发布目标切到新库。

4.3 在 Nexus 3 里发起迁移并盯日志

Nexus 3 侧的操作入口在系统管理里,需要先启用迁移相关的能力,然后填写升级代理的地址和凭据,选择要迁移的仓库,点击开始。发起之后不要急着关掉页面,进度是通过后台任务跑的,页面只是一个观察窗口。

真正的观察点在日志里。我会开两个终端,一个跟 Nexus 3 的日志,一个跟升级代理的日志,重点看三类信息:单个仓库的迁移是否开始、是否有报错重试、整体进度是否在推进。如果某个仓库长时间没有任何输出,基本可以判断是卡住了,这时候要有心理准备——官方工具在这个版本上对中断恢复的支持并不理想,中途停了通常得重新跑这个仓库。

所以我的策略是先迁小的、不重要的仓库,确认流程稳定之后再迁大的。第一次迁的就是那个只有几百兆的第三方包仓库,整个流程几分钟就走完了,验证成功之后才动几十 G 的中央仓库代理。这个顺序看起来浪费时间,实际上是把风险控制在自己能承受的范围内。

4.4 迁移后的仓库核对清单

迁移结束不等于迁移成功。我在 Nexus 3 里按下面这张清单逐项核对,每一项都实际点进去看过。

核对项检查方法常见异常
仓库数量与类型Repositories 页面逐个对照 Nexus 2 的清单代理型仓库被迁成了托管型
代理仓库的 remote URL打开仓库配置看远程地址地址为空或指向错误的上游
内容条数看仓库的组件数是否与预期量级相符数量只有一小部分,说明中途失败
group 成员打开 group 配置看成员列表新迁进来的仓库没被加进 group
匿名访问权限用不带凭据的请求试拉一个包返回 401
快照仓库内容打开几个老快照版本看是否完整同一个版本出现多条重复记录

其中 group 成员这一项特别容易被忽略。迁移过来的仓库不会自动加入已有的 group,需要你手工在 group 的配置里把它们加进去。我见过有人迁移完之后客户端一直拉不到包,排查了半天才发现是 group 里根本没有新仓库。

5. 没有升级代理时的兜底方案:脚本搬运

5.1 用 Nexus 2 的 REST API 拉取清单

官方工具搞不定的仓库,我准备了一套自己搬的方案。第一步是拿到完整的组件清单。Nexus 2 的接口里可以按仓库列出内容,但更省事的做法是直接读磁盘上的目录结构,因为 Nexus 2 的存储就是按坐标组织的文件树,路径本身就是元数据。

SRC=/data/nexus/sonatype-work/nexus/storage/releases find "$SRC" -name '*.pom' -type f | head -20

输出大概长这样:org/example/tool/1.2.3/tool-1.2.3.pom。从路径就能反推出坐标:最后一段是版本,倒数第二段是 artifactId,前面的目录层级拼起来就是 groupId。这个规律非常稳定,用它写脚本比调接口可靠得多。

5.2 用 Nexus 3 组件上传接口回灌

Nexus 3 提供了组件上传接口,可以按仓库名提交一组文件,Maven 格式的上传需要同时带上坐标参数和文件。用脚本按坐标逐组提交是最直接的方式,下面是我实际用的一段 Python 骨架,思路是把目录里的文件按 artifact 分组,再用 multipart 提交。

import os, requests NEXUS3 = "http://new-nexus:8081/service/rest/v1/components" AUTH = ("deployer", "password") REPO = "releases" ROOT = "/data/nexus/sonatype-work/nexus/storage/releases" def submit(group, artifact, version, files): data = { "maven2.groupId": group, "maven2.artifactId": artifact, "maven2.version": version, } for i, path in enumerate(files, start=1): data[f"maven2.asset{i}"] = (os.path.basename(path), open(path, "rb")) r = requests.post(NEXUS3, params={"repository": REPO}, auth=AUTH, files=data) print(group, artifact, version, r.status_code) for dirpath, _, filenames in os.walk(ROOT): poms = [f for f in filenames if f.endswith(".pom")] if not poms: continue rel = os.path.relpath(dirpath, ROOT) parts = rel.split(os.sep) if len(parts) < 3: continue group = ".".join(parts[:-2]) artifact, version = parts[-2], parts[-1] files = [os.path.join(dirpath, f) for f in filenames] submit(group, artifact, version, files)

这里有几个实操细节。路径层级少于三层的目录要跳过,那是仓库根目录的元数据文件,不是真实组件。每个 artifact 的文件要一次性提交完,只传 jar 不传 pom 会在 Nexus 3 里生成一个缺少依赖信息的组件,后续别人拉下来照样报错。另外快照的版本号需要做一次还原,因为磁盘上是带时间戳的形式,要把它变回以-SNAPSHOT结尾的版本号,否则 Nexus 3 会把它当成一个正式版本存进去。

5.3 用 Maven 自身的 deploy 做小批量搬运

接口脚本写起来有点重,如果只是零星的几个包,用 Maven 自己的部署命令更省事。它能直接把本地的 jar 和 pom 推到你指定的仓库,坐标全部通过参数传入,不需要写代码。

mvn deploy:deploy-file \ -Durl=http://new-nexus:8081/repository/releases \ -DrepositoryId=nexus3 \ -DgroupId=org.example -DartifactId=tool -Dversion=1.2.3 \ -Dpackaging=jar \ -Dfile=tool-1.2.3.jar \ -DpomFile=tool-1.2.3.pom

这个方式的问题是每条命令都要启动一次 JVM,几百个包跑下来时间很长,而且一旦某个包坐标推错,事后很难查。所以我只用它处理那些脚本搬运失败的零星包,批量场景还是用接口。

提示:无论是接口还是 deploy 命令,回灌完成后都要去 Nexus 3 里搜一下这个坐标,确认能搜到、能下载、pom 里的依赖信息完整。只上传成功不代表组件是可用的。

6. 客户端切换:settings.xml、CI 与 IDE 的改动点

6.1 仓库地址变了,镜像配置必须跟着改

这是客户端侧最大的变化,也是所有构建报错的根源。Nexus 2 的对外地址形如/nexus/content/groups/public/,而 Nexus 3 的地址结构变成了/repository/仓库名/,中间那段content/groups没有了。老客户端的配置如果不改,会在拉取时直接 404,而且报错信息往往含糊,看不出是地址问题。

<mirrors> <mirror> <id>nexus3</id> <name>internal nexus3</name> <url>http://new-nexus:8081/repository/maven-public/</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors>

关于mirrorOf的取值,我的建议是不要图省事写*。写*会把所有仓库请求都强制走私库,包括一些插件仓库,一旦私库断掉,所有构建全部失败,而且排查时很难看出是哪一类请求受影响。只把中央仓库的地址镜像掉,其他仓库正常直连或者按需代理,稳定性更好。

凭据配置放在同一个文件里,注意用户名密码要和 Nexus 3 里创建的部署账号一致。密码建议通过环境变量或者外部的凭据文件注入,直接明文写在 settings.xml 里然后提交到代码库,是很多人踩过的坑。

<servers> <server> <id>nexus3</id> <username>${env.NEXUS_USER}</username> <password>${env.NEXUS_PASS}</password> </server> </servers>

6.2 Jenkins、GitLab CI 这类流水线的改造点

流水线侧的改动比本地开发更需要注意,因为它们是批量执行的,一个配置错误会影响所有任务。我按这个顺序处理:先在流水线里把 Nexus 地址从环境变量或者共享配置中提取出来,确认只有一个地方需要改;然后在一两个非核心任务上试运行;确认无误再全量切换。

代理设置也要同步更新。如果流水线跑在没有外网的环境里,Maven 的代理参数和私库地址是两套东西,改了一个忘了一个,表现就是"私库能连、插件下载失败"。另外,Nexus 3 的部署路径也变了,原来指向 releases 仓库的上传地址需要改成新的/repository/形式,这个如果不改,构建本身能成功,但最后一步发布依赖会失败。

6.3 IDEA 与本地缓存的清理

本地的 IDE 是另一个高频出问题的地方。切换私库之后,本地已经缓存的依赖元数据还指向老地址,表现就是"命令行能构建,IDEA 里一片爆红"。这时候不要急着怀疑配置,先把本地仓库里对应 artifact 的元数据清掉再重新拉。

rm -rf ~/.m2/repository/org/example mvn -U clean install

-U参数强制更新快照和元数据,切换私库后的第一次构建建议都加上。如果 IDEA 依然爆红,检查一下它的 Maven 配置用的是不是全局的 settings.xml,有些项目里会自带一份项目级的配置文件,优先级更高,容易造成"我明明改了全局配置但没生效"的困惑。

7. 常见问题与排查实录

7.1 迁移中断、卡死与重试

迁移过程中最常见的问题就是某个仓库卡住不动。判断方法是看日志有没有新的输出,如果十分钟以上没有任何进展,基本可以确认是卡住了。原因通常有三种:仓库里有一个体积异常大的文件、磁盘写入变慢、或者升级代理与 Nexus 2 之间的连接被中间设备掐断。

处理上我的建议是不要等,直接停掉这次任务的这个仓库,把大体积文件单独拎出来手工搬,剩下的内容重新跑一次。等待的代价往往比重新跑更大,因为迁移窗口的时间是有限的。另外,正式迁移之前一定要给磁盘预留足够的写入性能,如果用的是网络存储,先做一次写入测试再开始。

7.2 401 和 403 的排查顺序

这两个状态码对应的原因完全不同,排查顺序也不一样。401 是没认证,通常是客户端没有带凭据,或者 Nexus 3 里匿名访问被关掉了但客户端还按匿名的预期在请求。403 是认证过了但没权限,多半是部署账号没有被授予对应仓库的写权限,或者角色配置漏了某个仓库。

排查的时候按这个顺序走:先用curl带凭据直接请求一个具体文件,确认是不是客户端配置的问题;再检查 Nexus 3 里这个账号的角色和权限;最后确认这个仓库本身有没有特殊的访问策略。我遇到过一次典型案例:账号权限完全正确,但因为是往 group 地址上传,而 group 本身不允许写入,导致一直返回 403。上传必须走托管仓库的地址,不能走 group。

7.3 校验和、元数据与快照的坑

校验和不匹配是回灌过程中最烦人的问题之一。表现是文件传上去了,但客户端下载时报校验失败。原因通常是源文件在 Nexus 2 里就已经有问题,或者传输过程中断导致文件不完整。处理办法是先对比源文件和目标文件的哈希值,确认是哪一端的问题,必要时在客户端把校验策略放宽到警告级别,但这是临时手段,不能长期依赖。

快照的问题更隐蔽。Nexus 2 里同一个快照版本每次发布都会生成一份带时间戳的文件,迁移到 Nexus 3 之后,这些历史文件可能会被识别成多条独立记录,结果就是这个快照版本下挂了一堆内容。如果这些历史快照没有保留价值,最干净的做法是迁移完成后清理掉,让后续的发布重新生成一份。判断是否有价值的标准很简单:有没有业务方明确说"我需要回滚到某个具体的旧快照",没有的话就清。

7.4 管理员密码忘掉之后怎么办

这是个很高频的问题。3.12.0 这个版本第一次启动有默认的管理员凭据,登录后会强制修改。如果改完忘了,或者其他同事改过没同步,常规做法是停服务、在数据目录里定位到存放安全配置的那部分数据、把它清掉,然后重启,让系统重建一套默认的安全配置。重启后你会拿到一个新的默认管理员账号。

注意:这个操作会把用户、角色、权限配置全部重置,同时你之前配置的 token 也会失效。它是找回访问权的最后手段,做之前务必确认数据目录已经备份,并且清楚后续要重建哪些账号和权限。

7.5 迁移之后的性能调优记录

迁移本身只是第一阶段,迁移完之后大量的查询和下载会把新实例压出问题。我在迁移完成后做了三件事。第一,调整 JVM 参数,按第 2 节那张表的建议值设置堆和直接内存,并加上适合大内存的垃圾回收策略。第二,把数据目录和日志目录分到不同的物理盘上,避免日志写入影响内容读取。

第三,重建索引。迁移过来的组件在初始状态下搜索性能并不好,跑一次索引重建类的任务明显能改善。同时把清理类的计划任务配起来,定期清理代理仓库里长期没人访问的缓存内容,控制住磁盘增长。这几步做完,热数据的响应速度会有肉眼可见的提升。

现象可能原因处理方向
迁移任务长时间无输出超大文件或磁盘写入瓶颈单独手工搬运该文件,重跑仓库
客户端 404仓库地址结构没改换成新的 repository 路径
客户端 401未带凭据或匿名被关配置凭据或调整匿名策略
客户端 403权限不足或往 group 上传补齐角色权限,改用托管仓库地址
搜索不到已迁移的组件索引未重建触发索引重建任务
磁盘快速上涨缓存未清理配置清理类计划任务

8. 双轨并行与回滚预案

8.1 灰度切换的顺序

新旧两套私库并行一段时间,是我这次迁移里最满意的一个决定。切换顺序按影响面从小到大排:先切我自己的开发机,用两三天确认日常构建没有问题;再切一两个非核心项目的 CI;最后才是核心项目的流水线和全团队。每切一批,观察一天再进下一批。

这个顺序的意义在于,一旦某批出现问题,你立刻知道是哪一类使用者受影响,而且可以精准地让他们改回旧地址,不会影响其他人。如果一上来就全量切换,出问题时所有人同时构建失败,你连问题出在哪一类客户端上都判断不出来。

8.2 回滚到底怎么回

回滚这件事要在开始之前就想好,而不是出事之后再想。我的做法是:整个灰度期内 Nexus 2 保持运行且保持只读,所有客户端配置里的旧地址都保留着,只是通过流水线的变量控制实际用哪个。这样回滚的操作就是改回一个变量值,重启一下任务,成本极低。

需要接受的一个现实是:迁移之后在新库里发布的新版本,回滚到旧库是带不回去的。所以灰度期内我要求团队尽量把新版本的发布压后,或者接受"回滚期间这部分版本需要手工补传到旧库"。这个约束在切换前就跟所有人说清楚,比出事之后解释要有效得多。

我自己做完这套迁移最大的体会是,真正花时间的从来不是敲命令,而是前期的盘点和后期的验证。工具能帮你搬数据,但搬完之后"这个仓库是不是完整、这个权限是不是对、这个地址是不是所有人都改了",只能靠一条一条核对。另外一个小技巧分享给要动手的人:把整个迁移过程写成一份带命令的清单文档,每一步后面留一个勾选框,迁移当天照着往下走,比凭记忆操作可靠得多,而且下次再遇到类似的任务,这份文档就是现成的操作手册。后续如果要把 npm 或者 docker 仓库也收进同一个实例,其实就是在 Nexus 3 里新建对应格式的仓库再配一遍权限,迁移的这套思路完全可以复用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询