☰
Nexus私服升级迁移实战:从备份到验证的完整避坑指南
2026/10/20 8:59:15 网站建设 项目流程

最近刚把团队的老私服从 Nexus 2.x 迁到了 3.x,顺带把部署方式和备份策略也重新整理了一遍。做 maven 私服升级这件事,标题看着就四个字,真正动起手来牵扯的东西比想象中多得多:备份、迁移、权限、仓库 URL、团队构建配置,哪一环没照顾到,升级完当天就会被全组工程师轮流问候。这篇把这次的完整操作记录下来,包括踩过的坑和排查过程,给正在准备做 nexus 服务升级的同学一份能直接照着走的参考。

1. 升级前先想清楚:你的私服属于哪种升法

1.1 三种常见的升级类型

我在动手前先花了一天时间确认私服到底属于哪种升级场景,因为不同场景的难度和风险完全不一样。

第一种是 Nexus 2.x 迁移到 Nexus 3.x。这是最折腾的一种。Nexus 2 的数据存储、仓库布局、权限模型和 Nexus 3 差别很大,官方虽然有自动迁移工具,但迁移完仍然需要大量人工检查。我这次就是这种类型,所以后面会重点讲。

第二种是 Nexus 3.x 内部的跨版本升级。比如从 3.29 升到 3.4x 或 3.6x 这种。底层数据格式是兼容的,理论上停服、换安装包、启动就行,但跨的版本太多时也会出现数据库需逐步迁移的情况,不能想当然。

第三种是紧急安全补丁升级。这种通常不涉及仓库数据迁移,但最怕没有备份就直接上生产。我见过有人为了省事跳过备份,结果升级包解压时磁盘满了,服务起不来,又没有回滚方案,只能原地修,压力非常大。

先判断你属于哪种,再决定下一步怎么做,而不是拿到安装包就直接替换。升级类型判断错了,后面所有步骤都可能白费。

1.2 动手前先回答这几个问题

在开始任何操作之前,我会把下面这些问题列成清单,逐项确认:

  • 当前跑的是哪个大版本、哪个小版本,是否能从管理界面或安装目录直接看到
  • 目标版本是什么,目标版本对 JDK 版本有什么要求
  • 私服所在服务器的 CPU、内存、磁盘空间是否达标
  • 私服数据目录和安装目录是否在同一块磁盘,空间余量有多少
  • 除了 Maven 仓库,私服上还跑了哪些格式的仓库,比如 npm、Docker、NuGet
  • 团队里的settings.xml或构建脚本里配置的私服地址是什么格式,升级后会不会变
  • 私服有没有配置 LDAP、外部数据库、自定义任务、自定义路由规则

这些问题不用全部搞懂才动手,但至少要做到心里有数。尤其是磁盘空间和仓库地址这两项,是升级失败和升级后业务报错的主要来源。

我这次升级前就发现一个明显问题:私服数据目录所在磁盘只有不到 10% 的空闲,而安装包解压后需要额外占用至少一个数据目录的容量。当时先清理了旧的日志和临时文件,才敢开始升级。

2. 别急着动生产:备份做到什么程度才算稳

2.1 该备份的东西

很多人以为备份就是把安装目录打个包,实际上私服的核心数据根本不在安装目录里。Nexus 2 的数据默认在sonatype-work/nexus目录下,Nexus 3 的数据默认在sonatype-work/nexus3目录下。真正要备份的是这个数据目录,而不是程序目录。

具体来说,我备份的范围包括:

  • Blob 存储或文件存储目录,也就是实际存放组件文件的目录,通常体积最大
  • 数据库文件,包括组件元数据、仓库配置、用户信息、任务信息,这个文件虽然不大,但坏了整个私服就废了
  • etc配置目录,里面有端口、上下文路径、HTTP 代理等设置
  • 密钥目录,比如keystore,如果丢了,已上传组件的校验信息可能错乱
  • 所有定时任务的配置、LDAP 连接配置、匿名访问开关等,这些在部分迁移场景下不会被自动带过去
  • 旧版本的完整安装目录,我习惯把整个目录都备一份,一是为回滚做准备,二是迁移工具出问题时还能从旧环境里反查配置

我见过有人只备份了 blob 目录,恢复时发现数据库文件和 blob 文件对不上,结果组件列表是空的,文件还在磁盘上就是无法索引。这种恢复比没有备份更折磨人。

2.2 我常用的备份命令与验证方法

备份命令本身并不复杂,关键是验证。我这边实际执行的是先停服再打包,因为运行中的私服数据文件可能处于写入状态,热备份容易出现文件不一致。

# 停止服务,这里以 systemd 方式为例 sudo systemctl stop nexus # 备份数据目录,使用 tar 保留权限和属主 sudo tar -czf /backup/nexus-data-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt sonatype-work # 备份安装目录,尺寸小,但回滚时用得上 sudo tar -czf /backup/nexus-install-$(date +%Y%m%d-%H%M%S).tar.gz -C /opt nexus-2.14.5-02 # 生成校验文件,确认备份没有损坏 sha256sum /backup/nexus-data-*.tar.gz > /backup/checksum.txt

打完包之后,我会实际做一次恢复演练。很多人觉得备份文件存在就算完成了,其实备份是否可用,只有在恢复的时候才知道。我在升级前会找一台同样的服务器,把备份解压出来,启动一个临时私服实例,确认管理界面能登录、仓库列表能看到、能下载一个组件。这个过程花不了多长时间,但能避免在升级失败需要回滚时才发现备份是坏的。

另外注意一点,私服数据目录里往往有大量小文件,tar 打包时间可能比预期长很多。我建议在打包前先估算数据总量,至少预留出打包时间的两倍,再安排停机窗口。

2.3 升级窗口怎么安排

私服虽然是内部工具,但所有开发人员的构建都依赖它。升级窗口安排不好,团队上午发布就卡在依赖下载上,这种失误会非常影响信任。

我的建议是选在迭代间隙的下午或者傍晚,避开发布日和工作日上午的高峰。窗口期至少预留四到六小时,不要想着一小时搞定,因为升级过程中很难保证不遇到意外。

通知也要提前做。至少提前一个工作日在团队群或者周知邮件里说明升级的时间段、影响范围、预计时长,建议所有人在这期间不要触发新的构建和发布。特别是自动化流水线,如果有定时构建任务,也要暂时停掉或改到窗口外。

还有一个很重要的习惯:升级前把旧版本目录完整保留,不要在确认新版本稳定之前删除。回滚方案应该是“旧目录原地恢复”而不是“重新安装旧版本再导入数据”,后者的复杂度完全不同。

3. 实操:两种升级路线的完整步骤

3.1 路线 A:Nexus 2.x 迁移到 Nexus 3.x

这次的主线是从 Nexus 2.x 迁移到 Nexus 3.x。老版本安装目录已经运行了三四年,上面有大量快照版本和第三方依赖。整个迁移过程我分成几个阶段来做。

首先,停止 Nexus 2 服务和它的后台进程,确认没有残留进程占用端口。接着按上一节的方法完成备份,这一步不能跳过。

然后开始安装 Nexus 3。我选择的是官方提供的 tar.gz 包,解压到/opt目录下。这里要注意解压后的目录属主,如果用root解压,但服务是用nexus用户运行的,启动时会因为没有写权限而失败。我每次都执行chown -R nexus:nexus /opt/nexus-3.x.x来修正属主。

安装完成后先不急着迁移数据,而是先把 Nexus 3 启动一次,确认它能正常初始化。Nexus 3 默认端口是 8081,和 Nexus 2 一样,如果老服务还在运行,端口冲突会直接导致启动失败。我当时的处理方法是先让 Nexus 2 停下来,把 Nexus 3 的端口临时改成 8082 先跑起来,确认基础功能正常后,再改回 8081 做正式切换。

第一次启动 Nexus 3 后,管理员密码会生成在数据目录下的admin.password文件里,首次登录后会要求修改密码。这个流程和 Nexus 2 不一样,很多从 2.x 过来的人会卡在这里。

接着是数据迁移这一步。Nexus 3 管理界面的迁移入口支持从 Nexus 2 实例导入数据,前提是 Nexus 2 能通过 REST 接口被访问。实际操作时,我在 Nexus 2 侧配置了迁移所需的插件,然后在 Nexus 3 的迁移页面填入 Nexus 2 的地址和管理员账号,选择需要迁移的仓库、用户、角色和配置,开始执行。

迁移过程中最花时间的其实是组件文件的复制。我们私服上有大量小文件,总共迁移了三个多小时。迁移完成后,我第一时间检查了仓库类型和 URL 路径。Nexus 2 的仓库访问地址通常是http://ip:8081/nexus/content/groups/public,而 Nexus 3 是http://ip:8081/repository/public/。这个变化导致了几乎所有开发机器上的settings.xml都要改,这也是这次升级中工作量最大的部分。

最后是验证。我用一个测试项目分别执行了 Maven 的mvn dependency:get和mvn deploy,确认能拉取第三方依赖、能上传快照包、能从 group 仓库中解析到组件。验证通过后,才把 Nexus 2 彻底停掉。

3.2 路线 B:Nexus 3.x 内部跨版本升级

如果你本来就是 Nexus 3,只是在 3.x 内部做小版本或跨大版本升级,操作会简单不少。这个流程我也反复练过,思路是停服、备份、替换安装目录、启动。

假设旧版本安装在/opt/nexus-3.29.2-02,数据目录在/opt/sonatype-work/nexus3。升级时先停服,然后把旧安装目录改名作为备份,再解压新版本安装包到/opt/nexus-3.49.0-01,保持数据目录不变,最后直接启动。

# 停服 sudo systemctl stop nexus # 保留旧安装目录,不作为主目录使用 sudo mv /opt/nexus-3.29.2-02 /opt/nexus-3.29.2-02.bak # 解压新版本到 /opt sudo tar -xzf nexus-3.49.0-01-unix.tar.gz -C /opt # 修正属主 sudo chown -R nexus:nexus /opt/nexus-3.49.0-01 # 把数据目录保留在原处,不需要移动 # 启动新版本 sudo systemctl start nexus

这里最关键的一点是数据目录不要跟着安装目录一起动。Nexus 3 的数据目录位置默认是通过安装目录的上级目录来定位的,具体启动脚本路径可能不太一样,所以在替换安装目录时,最好先确认新版本的启动脚本读取的数据目录路径没有变化。我在某次测试升级时,因为新旧版本的启动脚本改动比较大,数据目录被当成了空目录初始化,等于新建了一个空私服。遇到这种情况不要慌,停服后把原来的数据目录复制回去再启动就行。

另外,跨版本的升级不建议跳得太多。如果是从 3.0 早期版本直接升到 3.6x 这种跨度,官方通常建议按大版本逐级升级,因为底层数据库文件可能需要在特定版本上做一次格式迁移。我在非生产环境试过一次跨大版本直升,启动时日志里出现了数据库文件版本不兼容的报错,最后还是老老实实按版本区间逐级升上去了。

3.3 Docker 部署场景的升级差异

现在很多团队用 Docker 部署 Nexus 私服,这部分单独说一下。Docker 方式升级的逻辑也是换镜像,但要注意数据卷的完整性和权限。

一般部署时,宿主机的某个目录会挂载为容器里的/nexus-data。升级时先拉取新版本镜像,然后停掉旧容器,保留挂载目录不变,用新镜像和相同的数据卷参数重新启动。

# 先拉取新版本镜像 docker pull sonatype/nexus3:3.49.0-01 # 停旧容器 docker stop nexus docker rm nexus # 用新镜像启动,保留原挂载卷 docker run -d \ --name nexus \ -p 8081:8081 \ -v /data/nexus-data:/nexus-data \ sonatype/nexus3:3.49.0-01

这里最容易出问题的就是权限。不同版本的镜像基础系统用户 ID 可能不同,如果宿主机挂载目录的属主和容器内进程期望的属主不一致,就会出现权限不足,Nexus 无法写入数据。启动后看一眼日志,如果发现大量Permission denied,基本可以确定是权限问题,需要调整挂载目录属主。

Docker 部署的另一个注意点是端口映射和上下文路径。很多人通过 Nginx 反代到容器,升级后如果上下文路径变了,Nginx 侧的配置也要同步调整。我在 docker 升级后经常因为忘记改反代配置,导致管理界面访问 404。

不管用哪种部署方式,升级后的第一次启动都会比平时慢很多,因为 Nexus 3 需要重建搜索索引。日志里会看到一堆索引相关的输出,这属于正常现象,不要太早判断升级失败而强制重启。

4. 升级后最容易踩的坑和排查实录

升级完之后问题并不会立刻消失,接下来几个小时的观察期才是最考验人的。我把这次和以往遇到的典型问题做成了一张排查表,方便对照。

症状常见原因排查思路
服务起不来,日志报端口被占用旧服务没停干净,或其他进程占用端口用netstat -tlnp | grep 8081确认占用进程,停掉后再启动
管理界面能打开,但仓库列表为空数据目录路径变了,服务初始化了新数据目录查看启动日志确认读取的数据目录路径,把原数据目录复制回去
团队构建时下载依赖 404旧 URL 路径是/nexus/content/...,新版本是/repository/...更新所有settings.xml和构建脚本里的镜像地址
迁移后部分用户登录失败用户密码加密方式或 LDAP 配置没有完整迁移重新配置 LDAP 连接,管理员手动重置本地用户密码
磁盘空间突然不够升级产生大量日志和索引文件,或原备份占用了大量空间用df -h查看分区占用,清理临时文件和旧备份
定时任务在迁移后消失迁移工具不会带走全部任务配置对照旧实例的任务列表,手动新建缺失的任务
首次启动特别慢,界面半天打不开索引重建和数据迁移耗时较长查启动日志确认是否在跑索引任务,耐心等待

这里我详细说几个实际遇到的坑。

第一个是 URL 路径变化引发的连锁问题。我们团队有多条构建流水线直接在脚本里写死了私服地址,升级后第一轮构建几乎全军覆没,报错都是 404。这个问题的根源是 Nexus 2 和 Nexus 3 的仓库 URL 设计完全不同,没法通过配置直接兼容。解决办法只能是提前排查所有引用私服地址的地方,包括settings.xml、pom.xml里的 repository 地址、流水线脚本和 Docker 构建参数。升级完成后再用一条命令全局搜一遍,确认没有漏掉的旧地址。

第二个坑是匿名访问策略。Nexus 3 默认的匿名访问策略和很多从 2.x 迁移过来的配置不一样。如果团队以前依赖匿名可以拉取公开仓库,升级后会发现需要登录了,让很多构建脚本直接报 401。这个可以通过管理界面的匿名访问开关来调整,但需要想清楚安全性再动,不要为了省事直接打开匿名上传。

第三个是数据库文件版本不兼容。跨版本升级时,新版本启动会尝试自动迁移数据库文件。如果迁移失败,日志里会有明确的数据库版本提示。我遇到过一次因为跳的版本太多导致的迁移失败,最后是按版本区间逐级升级才解决。所以升级前一定先查清楚当前版本到目标版本之间是否有强制要求的分步升级路径。

第四个是关于 Blob Store 的容量显示。升级后有些仓库显示的已用空间和之前对不上,这时候可以跑一次压缩 Blob Store 的任务,让系统重新计算大小。这不影响数据完整性,纯粹是统计口径变化。

5. 升级验证清单与收尾建议

5.1 构建侧验证清单

升级完成后,我会用一个干净的 Maven 项目从零开始验证整个链路,而不是只登录管理界面看一眼就宣布成功。具体验证项包括:

  • 能通过私服的 group 仓库解析到一个第三方依赖,比如mvn dependency:get -Dartifact=junit:junit:4.13.2
  • 能向私服的 releases 仓库发布一个测试构件
  • 能向私服的 snapshots 仓库发布一个测试快照,然后再次拉取到最新版本
  • Gradle 项目也能正常拉取依赖,不要只测 Maven
  • 如果私服同时代理了中央仓库,确认代理仓库的缓存和远程更新都正常,避免换台新机器就拉不到依赖

我会直接跑一遍完整的mvn clean deploy,把本地构建、依赖解析、发布上传这一整条链路都走通。这一步做完,就有把握说私服对外可用了。

5.2 管理侧验证清单

管理侧同样需要逐项检查,包括:

  • 所有旧仓库都迁移成功,类型和 Blob Store 的对应关系正确
  • 用户、角色的权限和迁移前一致,关键用户能正常登录
  • LDAP 配置是否生效,能不能同步新的用户
  • 定时任务列表完整,尤其是仓库清理任务和索引重建任务
  • 匿名访问策略是否符合团队预期
  • 磁盘空间是否充足,日志目录是否增长异常
  • 备份任务是否配置了新的私服信息,备份能正常执行

我建议从升级当天开始观察至少一周,每天看一下磁盘空间和日志,确认没有慢性的资源耗尽问题。

5.3 旧版本清理与回滚预案

升级验证完成后,不要急着删除旧版本和备份文件。我一般保留至少一周,确认新版本运行完全稳定后,再执行清理。

回滚预案也要提前写好。如果新版本出了问题,处理思路是停掉新服务,把备份的数据目录恢复原位,旧安装目录改回正式名称,重新启动旧版本。流程不复杂,但需要在升级前实际演练一次,不要在出问题时临时翻文档。

磁盘空间紧张的时候,保留整套旧版本备份确实很占地方,但和出问题时无法回滚的代价比起来,这点空间成本是值得付的。

后续如果再把私服版本往上走,流程和这次差不多,核心还是那几条:先备份、再升级、后验证。备份和数据目录的路径搞清楚,很多问题就解决了一大半。我个人在实际操作中的体会是,私服升级最难的从来不是执行命令,而是能不能把所有依赖它的环节都想到。你能把团队所有构建的地址都提前改好,把数据备份真正做到可恢复,这次升级其实已经成功了一大半。

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

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

立即咨询