如何使用 Nexus 备份和恢复 Nexus

Deprecated: Nexus 3.81 (nexus-ce-operator v3.81.1 and v3.81.2)

由于 Nexus 3.81 Community Edition 的限制性限制,该版本已被弃用。一旦使用达到配额限制(总组件数 100,000 和每日请求数 200,000),实例将无法正常工作。

如果您已经升级到 3.81 版本,请按照回滚到 Nexus 3.76指南进行降级。

有关 Community Edition 限制的更多信息,请参见Community Edition Limitations

前提条件

从集群中卸载 Nexus operator。

kubectl get subscription --all-namespaces | grep nexus-ce-operator | awk '{print "kubectl delete subscription "$2" -n "$1}' | sh

# 输出:
# subscription.operators.coreos.com "nexus-ce-operator" deleted
为什么要卸载 Nexus operator?

在备份和恢复过程中,Operator 可能会对 Nexus 资源进行协调,干扰操作。如果不卸载 Operator,可能会出现以下问题:

  1. Operator 可能会基于 Nexus CR 重新创建或重启工作负载,打断备份/恢复过程,可能导致数据不一致。
  2. 您临时删除的一些资源(例如 Service)可能会被重新创建,或者与从备份恢复的资源(例如 Ingress)冲突。
卸载 Nexus operator 的影响

卸载 Operator 后,对 Nexus CR 的修改将不会生效,例如调整资源或存储大小。

卸载 Operator 不会导致现有实例出现故障。

备份

备份包含五个步骤:

  1. 如果尚未卸载,先从集群中卸载 Nexus operator。
  2. 在 Nexus Web 上创建备份任务。
  3. 删除 nexus 实例的服务以防止数据变更。
  4. 备份 nexus 数据并验证备份。
  5. 备份完成后恢复 nexus 实例。

在 Nexus Web 上创建备份任务

以管理员用户登录 Nexus Web UI。导航至 Settings -> System -> Tasks -> Create task -> 选择 Admin - Backup H2 Database,填写:

  • 任务启用:true
  • 任务名称:nexus-backup(或任意名称)
  • 通知邮箱:(可选)user@example.com
  • 发送通知条件:(可选)Failure
  • 位置:/nexus-data 下的任意子目录(例如 /nexus-data/backup-dir
  • 任务频率:Manual

删除 nexus 实例服务以防止备份期间数据变更

为防止备份期间写入,临时停止实例的服务端点,删除前端 pod 的 Service

export NEXUS_NAMESPACE=<要备份的 NEXUS 实例命名空间>
export NEXUS_NAME=<要备份的 NEXUS 实例名称>
export NEXUS_BACKUP_DIR=<上一步设置的备份任务位置>
export POD_NAME=$(kubectl -n ${NEXUS_NAMESPACE} get pod ${NEXUS_NAME}-nxrm-ha-0 -o jsonpath='{.metadata.name}')

kubectl delete service -l release=${NEXUS_NAME} -n ${NEXUS_NAMESPACE}

#输出:
# service "nexus-nxrm-ha" deleted
# service "nexus-nxrm-ha-hl" deleted

此操作不会删除 pod 或数据,仅停止外部流量。

备份 nexus 数据并验证备份

备份 blob 存储

mkdir -p nexus-backup/blobs
kubectl -n ${NEXUS_NAMESPACE} cp ${POD_NAME}:/nexus-data/blobs nexus-backup/blobs

备份节点 ID 密钥库

mkdir -p nexus-backup/node
kubectl -n $NEXUS_NAMESPACE cp ${POD_NAME}:/nexus-data/keystores/node nexus-backup/node

导出并备份数据库

export NEXUS_ADMIN_USER=admin
export NEXUS_ADMIN_PASSWORD=<admin-password>

kubectl exec -ti $POD_NAME -n $NEXUS_NAMESPACE -- curl -u $NEXUS_ADMIN_USER:$NEXUS_ADMIN_PASSWORD 'localhost:8081/service/rest/v1/tasks?type=h2.backup.task'

# 输出:
#{
#  "items" : [ {
#    "id" : "b379f8cb-ea52-4bae-9eed-84aed7686a63",
#    "name" : "nexus-backup",
#    "type" : "h2.backup.task",
#    "message" : null,
#    "currentState" : "WAITING",
#    "lastRunResult" : null,
#    "nextRun" : null,
#    "lastRun" : null
#  } ],
#  "continuationToken" : null
#}

export TASK_ID=b379f8cb-ea52-4bae-9eed-84aed7686a63 # 替换为上面输出中的任务 ID
kubectl exec -ti $POD_NAME -n $NEXUS_NAMESPACE -- curl -s -o /dev/null -w "%{http_code}\n" -u $NEXUS_ADMIN_USER:$NEXUS_ADMIN_PASSWORD -X POST localhost:8081/service/rest/v1/tasks/${TASK_ID}/run

# 代码	说明
# 204	任务已运行
# 404	任务未找到
# 405	任务已禁用
# 输出:
# 204

kubectl exec -ti $POD_NAME -n $NEXUS_NAMESPACE -- curl -u $NEXUS_ADMIN_USER:$NEXUS_ADMIN_PASSWORD localhost:8081/service/rest/v1/tasks/${TASK_ID}

#输出(lastRun 和 lastRunResult 会有所不同):
# {
#   "id" : "b379f8cb-ea52-4bae-9eed-84aed7686a63",
#   "name" : "nexus-backup",
#   "type" : "h2.backup.task",
#   "message" : "Backup embedded h2 database to the specified location",
#   "currentState" : "WAITING",
#   "lastRunResult" : "OK",
#   "nextRun" : null,
#   "lastRun" : "2025-11-03T15:21:50.302+00:00"
# }

kubectl exec -ti $POD_NAME -n $NEXUS_NAMESPACE -- ls $NEXUS_BACKUP_DIR

# 输出:
# nexus-2025-11-03-15-12-34.zip

然后从 pod 复制导出的文件:

mkdir -p nexus-backup/restore-from-backup
kubectl -n $NEXUS_NAMESPACE cp ${POD_NAME}:$NEXUS_BACKUP_DIR nexus-backup/restore-from-backup

验证备份内容

复制完成后,备份目录应至少包含以下文件夹:

  • nexus-backup/blobs
  • nexus-backup/node
  • nexus-backup/restore-from-backup

根据您的实例,目录内的文件名可能有所不同。

nexus-backup
├── blobs
   └── default
       ├── content
...
├── node
   ├── private.ks
   └── trusted.ks
└── restore-from-backup
    └── nexus-2025-11-03-15-12-04.zip

备份成功后,恢复 nexus 实例服务

进入 Administrator -> Marketplace -> Operator Hub 页面,切换到目标集群,然后重新部署 Alauda Build of Nexus Operator。

恢复

前提条件

确定目标命名空间,以及是否恢复到原实例(覆盖数据)或新实例。恢复期间确保 Operator 保持卸载状态,避免干扰。

恢复包含五个步骤:

  1. 如果尚未卸载,先从集群中卸载 Nexus ce operator。
  2. 删除 nexus 实例服务以防止恢复期间数据变更。
  3. 删除目标实例的现有数据。
  4. 重启 pod,让 Nexus 从备份恢复。
  5. 清理临时数据并恢复正常服务。

如果尚未卸载,先从集群中卸载 Nexus ce operator。

kubectl get subscription --all-namespaces | grep nexus-ce-operator | awk '{print "kubectl delete subscription "$2" -n "$1}' | sh

# 输出:
# subscription.operators.coreos.com "nexus-ce-operator" deleted

删除 nexus 实例服务以防止恢复期间数据变更

export NEXUS_NAMESPACE=<要恢复的 NEXUS 实例命名空间>
export NEXUS_NAME=<要恢复的 NEXUS 实例名称>
export POD_NAME=$(kubectl -n ${NEXUS_NAMESPACE} get pod ${NEXUS_NAME}-nxrm-ha-0 -o jsonpath='{.metadata.name}')

kubectl delete service -n $NEXUS_NAMESPACE -l release=$NEXUS_NAME

# 输出:
# service "nexus-nxrm-ha" deleted
# service "nexus-nxrm-ha-hl" deleted

删除目标实例的现有数据

删除目标 pod 中的现有数据,避免旧数据与恢复数据混合。如果权限限制无法在 pod 内删除,请根据您的存储类说明直接从挂载卷删除数据。

kubectl -n $NEXUS_NAMESPACE exec -it ${POD_NAME} -- \
  rm -rf /nexus-data/blobs \
         /nexus-data/keystores/node \
         /nexus-data/db/

如果必须直接在节点/PV 上删除,也请删除相同目录。

重启 pod,让 Nexus 从备份恢复

导入备份数据

重要提示

恢复数据时,请确保使用正确的数据库文件。

如果回滚到 Nexus 3.76,请使用回滚流程前一步创建的回滚数据库文件。详情见回滚到 Nexus 3.76

kubectl -n $NEXUS_NAMESPACE cp /tmp/nexus-restore/rolledback/nexus.mv.db ${POD_NAME}:/nexus-data/db/nexus.mv.db
kubectl -n $NEXUS_NAMESPACE exec -it ${POD_NAME} -- mkdir -p /nexus-data/db/
kubectl -n $NEXUS_NAMESPACE cp nexus-backup/blobs ${POD_NAME}:/nexus-data
kubectl -n $NEXUS_NAMESPACE cp nexus-backup/node ${POD_NAME}:/nexus-data/keystores
unzip nexus-backup/restore-from-backup/nexus-*.zip -d /tmp/nexus-restore
kubectl -n $NEXUS_NAMESPACE cp /tmp/nexus-restore/nexus.mv.db ${POD_NAME}:/nexus-data/db/nexus.mv.db

确认 pod 中以下目录包含数据:

  • /nexus-data/blobs
  • /nexus-data/keystores/node
  • /nexus-data/db/nexus.mv.db

重启 pod 以完成恢复

kubectl -n $NEXUS_NAMESPACE delete pod ${POD_NAME}

等待新 pod 启动并让 Nexus 完成内部恢复过程。

清理临时数据并恢复正常服务

确认数据已恢复且实例正常后,删除临时恢复文件,避免未来重启时重复导入:

kubectl -n $NEXUS_NAMESPACE exec -it ${POD_NAME} -- rm -rf /nexus-data/restore-from-backup

进入 Administrator -> Marketplace -> Operator Hub 页面,切换到目标集群,然后重新部署 Alauda Build of Nexus Operator。

登录 Nexus Web,检查所有仓库和数据是否完整。

故障排除

备份任务失败,出现 AccessDeniedException

检查任务状态时,如果看到 lastRunResult 为 FAILED:

kubectl exec -ti $POD_NAME -n $NEXUS_NAMESPACE -- curl -u $NEXUS_ADMIN_USER:$NEXUS_ADMIN_PASSWORD localhost:8081/service/rest/v1/tasks/${TASK_ID}
Defaulted container "nxrm-app" out of: nxrm-app, request-log, audit-log, tasks-log, chown-nexusdata-owner-to-nexus-and-init-log-dir (init)
{
  "id" : "0a8a4597-1cee-4f4c-8d86-6d81eb2cd8eb",
  "name" : "nexus-backup",
  "type" : "h2.backup.task",
  "message" : "Backup embedded h2 database to the specified location",
  "currentState" : "WAITING",
  "lastRunResult" : "FAILED",
  "nextRun" : null,
  "lastRun" : "2025-11-05T06:23:31.010+00:00"
}

可以查看任务日志获取更多细节:

kubectl logs $POD_NAME -n $NEXUS_NAMESPACE | grep $TASK_ID -A 10 -B 10
Defaulted container "nxrm-app" out of: nxrm-app, request-log, audit-log, tasks-log, chown-nexusdata-owner-to-nexus-and-init-log-dir (init)
2025-11-05 06:23:31,023+0000 INFO  [quartz-8-thread-20] *TASK org.sonatype.nexus.internal.datastore.task.H2BackupTask - Task configuration: {.name=nexus-backup, .id=0a8a4597-1cee-4f4c-8d86-6d81eb2cd8eb, .typeName=Admin - Backup H2 Database, .visible=true, .typeId=h2.backup.task, .notificationCondition=FAILURE, .updated=2025-11-05T06:19:54.814Z, .recoverable=false, .enabled=true, .message=Backup embedded h2 database to the specified location, location=/nexus/backup, .exposed=true, .created=2025-11-05T06:19:54.814Z}
2025-11-05 06:23:31,023+0000 INFO  [quartz-8-thread-20] *TASK org.sonatype.nexus.internal.datastore.task.H2BackupTask - Task log: /opt/sonatype/sonatype-work/nexus3/log/tasks/allTasks.log
2025-11-05 06:23:31,024+0000 ERROR [quartz-8-thread-20] *TASK org.sonatype.nexus.bootstrap.entrypoint.configuration.ApplicationDirectoriesImpl - Failed to create directory: /nexus/backup
2025-11-05 06:23:31,031+0000 WARN  [quartz-8-thread-20] *TASK org.sonatype.nexus.quartz.internal.task.QuartzTaskJob - Task 0a8a4597-1cee-4f4c-8d86-6d81eb2cd8eb : 'nexus-backup' [h2.backup.task] execution failure
java.lang.RuntimeException: java.nio.file.AccessDeniedException: /nexus

这表明 Nexus 没有权限写入指定的备份位置。请确保备份目录位于 /nexus-data 下。

进入 Administrator -> Marketplace -> Operator Hub 页面,切换到目标集群,重新部署 Alauda Build of Nexus Operator,登录 Nexus Web,修改备份任务,使用 /nexus-data 下的目录,例如 /nexus-data/backup