通过文件导出迁移项目的故障排除

如果您在使用通过文件导出迁移项目时遇到问题,请参阅以下可能的解决方案。

故障排除命令

使用 JID 查找有关导入状态和更多日志的信息:

# Rails console
Project.find_by_full_path('group/project').import_state.slice(:jid, :status, :last_error)
> {"jid"=>"414dec93f941a593ea1a6894", "status"=>"finished", "last_error"=>nil}
# Logs
grep JID /var/log/gitlab/sidekiq/current
grep "Import/Export error" /var/log/gitlab/sidekiq/current
grep "Import/Export backtrace" /var/log/gitlab/sidekiq/current
tail /var/log/gitlab/gitlab-rails/importer.log

由于不匹配,项目无法导入

如果导出的项目与项目导入之间的共享 runner 启用不匹配,则项目无法导入。

  • 确保在源项目和目标项目中都启用了共享 runner。
  • 导入项目时禁用父组上的共享 runner。

大型仓库的导入解决方法

最大导入大小限制可能会阻止导入成功。如果无法更改导入限制,您可以尝试此处列出的解决方法之一。

解决方法 1

以下本地工作流程可用于临时减少仓库大小以进行另一次导入尝试:

  1. 从导出创建一个临时工作目录:

     EXPORT=<filename-without-extension>
    
     mkdir "$EXPORT"
     tar -xf "$EXPORT".tar.gz --directory="$EXPORT"/
     cd "$EXPORT"/
     git clone project.bundle
    
     # Prevent interference with recreating an importable file later
     mv project.bundle ../"$EXPORT"-original.bundle
     mv ../"$EXPORT".tar.gz ../"$EXPORT"-original.tar.gz
    
     git switch --create smaller-tmp-main
    
  2. 要减小仓库大小,请处理这个 smaller-tmp-main 分支:识别和删除大文件交互式变基和修复,来减少提交次数。

     # Reduce the .git/objects/pack/ file size
     cd project
     git reflog expire --expire=now --all
     git gc --prune=now --aggressive
    
     # Prepare recreating an importable file
     git bundle create ../project.bundle <default-branch-name>
     cd ..
     mv project/ ../"$EXPORT"-project
     cd ..
    
     # Recreate an importable file
     tar -czf "$EXPORT"-smaller.tar.gz --directory="$EXPORT"/ .
    
  3. 将这个新的、较小的文件导入极狐GitLab。
  4. 在原始仓库的完整克隆中,使用 git remote set-url origin <new-url> && git push --force --all 完成导入。
  5. 更新导入的仓库的分支保护规则及其默认分支,并删除临时的 smaller-tmp-main 分支和本地的临时数据。

解决方法 2

note此解决方法不考虑 LFS 对象。

此解决方法不是尝试一次推送所有更改,而是:

  • 将项目导入与 Git 仓库导入分开
  • 将仓库增量推送到极狐GitLab
  1. 对要迁移的仓库进行本地克隆。在后面的步骤中,您将此克隆推送到项目导出之外。
  2. 下载导出并删除 project.bundle(其中包含 Git 仓库):

    tar -czvf new_export.tar.gz --exclude='project.bundle' @old_export.tar.gz
    
  3. 导入没有 Git 仓库的导出,要求您确认在没有仓库的情况下导入。
  4. 将此 bash 脚本保存为文件,并在添加适当的源后运行它。

    #!/bin/sh
    
    # ASSUMPTIONS:
    # - The GitLab location is "origin"
    # - The default branch is "main"
    # - This will attempt to push in chunks of 500MB (dividing the total size by 500MB).
    #   Decrease this size to push in smaller chunks if you still receive timeouts.
    
    git gc
    SIZE=$(git count-objects -v 2> /dev/null | grep size-pack | awk '{print $2}')
    
    # Be conservative... and try to push 2GB at a time
    # (given this assumes each commit is the same size - which is wrong)
    BATCHES=$(($SIZE / 500000))
    TOTAL_COMMITS=$(git rev-list --count HEAD)
    if (( BATCHES > TOTAL_COMMITS )); then
        BATCHES=$TOTAL_COMMITS
    fi
    
    INCREMENTS=$(( ($TOTAL_COMMITS / $BATCHES) - 1 ))
    
    for (( BATCH=BATCHES; BATCH>=1; BATCH-- ))
    do
      COMMIT_NUM=$(( $BATCH - $INCREMENTS ))
      COMMIT_SHA=$(git log -n $COMMIT_NUM --format=format:%H | tail -1)
      git push -u origin ${COMMIT_SHA}:refs/heads/main
    done
    git push -u origin main
    git push -u origin -—all
    git push -u origin -—tags
    

手动执行导出步骤

您通常通过 web 界面或通过 API 导出项目。使用这些方法导出有时会失败,而没有提供足够的信息来进行故障排除。在这些情况下,打开 Rails 控制台会话。 单独执行每一行,而不是一次粘贴整个代码块,这样您就可以看到每个命令返回的任何错误。

# User needs to have permission to export
u = User.find_by_username('someuser')
p = Project.find_by_full_path('some/project')
e = Projects::ImportExport::ExportService.new(p,u)

e.send(:version_saver).send(:save)
e.send(:repo_saver).send(:save)
## continue using `e.send(:exporter_name).send(:save)` going through the list of exporters

# The following line should show you the export_path similar to /var/opt/gitlab/gitlab-rails/shared/tmp/gitlab_exports/@hashed/49/94/4994....
s = Gitlab::ImportExport::Saver.new(exportable: p, shared:p.import_export_shared)

# To try and upload use:
s.send(:compress_and_save)
s.send(:save_upload)

项目上传成功后,导出的项目位于 /var/opt/gitlab/gitlab-rails/uploads/-/system/import_export_upload/export_file/ 中的 .tar.gz 文件中。

使用群组访问令牌时通过 REST API 导入失败

群组访问令牌不适用于项目或群组导入操作。当群组访问令牌启动导入时,导入失败并显示以下消息:

Error adding importer user to Project members.
Validation failed: User project bots cannot be added to other groups / projects

要使用导入 REST API,请传递常规用户帐户凭据,例如个人访问令牌

性能问题故障排除

通读下文的当前导入/导出的性能问题。

OOM 错误

内存不足 (OOM) 错误通常是由 Sidekiq Memory Killer 引起的:

SIDEKIQ_MEMORY_KILLER_MAX_RSS = 2000000
SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS = 3000000
SIDEKIQ_MEMORY_KILLER_GRACE_TIME = 900

导入状态 started,和以下 Sidekiq 日志表示存在内存问题:

WARN: Work still in progress <struct with JID>

超时

由于 Gitlab::Import::StuckProjectImportJobsWorker 将进程标记为失败而发生超时错误:

module Gitlab
  module Import
    class StuckProjectImportJobsWorker
      include Gitlab::Import::StuckImportJob
      # ...
    end
  end
end

module Gitlab
  module Import
    module StuckImportJob
      # ...
      IMPORT_JOBS_EXPIRATION = 15.hours.to_i
      # ...
      def perform
        stuck_imports_without_jid_count = mark_imports_without_jid_as_failed!
        stuck_imports_with_jid_count = mark_imports_with_jid_as_failed!

        track_metrics(stuck_imports_with_jid_count, stuck_imports_without_jid_count)
      end
      # ...
    end
  end
end
Marked stuck import jobs as failed. JIDs: xyz
  +-----------+    +-----------------------------------+
  |Export Job |--->| Calls ActiveRecord `as_json` and  |
  +-----------+    | `to_json` on all project models   |
                   +-----------------------------------+

  +-----------+    +-----------------------------------+
  |Import Job |--->| Loads all JSON in memory, then    |
  +-----------+    | inserts into the DB in batches    |
                   +-----------------------------------+