파일 익스포트 프로젝트 이주 문제 해결

파일 익스포트를 사용하여 프로젝트를 이주하는 중 문제가 발생하는 경우, 아래 가능한 해결책을 확인하세요.

문제 해결 명령어

JID를 사용하여 가져오기 상태와 추가 로그에 대한 정보를 찾으려면 레일즈 콘솔를 사용하세요.

Project.find_by_full_path('group/project').import_state.slice(:jid, :status, :last_error)
> {"jid"=>"414dec93f941a593ea1a6894", "status"=>"finished", "last_error"=>nil}
# 로그
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

불일치로 인한 프로젝트 가져오기 실패

인스턴스 러너 활성화 이 내보낸 프로젝트와 프로젝트 가져오기 사이에 일치하지 않으면 프로젝트 가져오기가 실패합니다. 이슈 276930를 검토하고 다음 중 하나를 실행하세요:

  • 소스 및 대상 프로젝트에서 인스턴스 러너가 활성화되어 있는지 확인하세요.
  • 프로젝트를 가져올 때 부모 그룹에서 인스턴스 러너를 비활성화하세요.

가져온 프로젝트에서 누락된 사용자

가져온 프로젝트에 사용자가 함께 가져오지 않는 경우 사용자 기여를 보존 요구 사항을 확인하세요.

누락된 사용자의 일반적인 이유는 사용자의 공개 이메일 설정이 구성되어 있지 않은 것입니다. 이 문제를 해결하려면 사용자에게 GitLab UI를 사용하여이 설정을 구성하도록 요청하세요.

수동 구성이 현실적이지 않을 경우 Rails 콘솔을 사용하여 모든 사용자 프로필을 공개 이메일 주소 사용으로 설정할 수 있습니다.

User.where("public_email IS NULL OR public_email = '' ").find_each do |u|
  next if u.bot?

  puts "#{u.username}의 현재 빈 공개 이메일을 #{u.email}(으)로 설정 중..."
  u.public_email = u.email
  u.save!
end

대형 리포지토리를 위한 가져오기 우회 방법

최대 가져오기 크기 제한은 가져오기가 성공적으로 완료되지 못할 수 있습니다. 가져오기 제한을 변경할 수 없는 경우 여기에 나열된 우회 방법 중 하나를 시도할 수 있습니다.

우회 옵션 1

다음 로컬 워크플로우를 사용하여 다른 가져오기 시도를 위해 리포지토리 크기를 임시로 줄일 수 있습니다.

  1. 내보낸 것으로 임시 작업 디렉토리를 만드세요:

    EXPORT=<확장자 없는 파일 이름>
    
    mkdir "$EXPORT"
    tar -xf "$EXPORT".tar.gz --directory="$EXPORT"/
    cd "$EXPORT"/
    git clone project.bundle
    
    # 나중에 가져올 수 있는 파일을 다시 생성하는 데 방해가 되지 않도록
    mv project.bundle ../"$EXPORT"-original.bundle
    mv ../"$EXPORT".tar.gz ../"$EXPORT"-original.tar.gz
    
    git switch --create smaller-tmp-main
    
  2. 리포지토리 크기를 줄이려면 smaller-tmp-main 브랜치에서 다음을 수행하세요: 크기가 큰 파일 확인 및 제거 또는 대화식 재베이스 및 픽싱으로 커밋 수를 줄입니다.

    # .git/objects/pack/ 파일 크기 줄이기
    cd project
    git reflog expire --expire=now --all
    git gc --prune=now --aggressive
    
    # 가져올 수 있는 파일을 다시 생성하는 준비
    git bundle create ../project.bundle <default-branch-name>
    cd ..
    mv project/ ../"$EXPORT"-project
    cd ..
    
    # 가져올 수 있는 새 파일을 다시 생성
    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

참고: 이 우회 방법은 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 스크립트를 파일로 저장하고 적절한 origin을 추가한 후 실행하세요.

    #!/bin/sh
    
    # 가정:
    # - GitLab 위치는 "origin"
    # - 기본 브랜치는 "main"
    # - 이는 전체 크기를 500MB로 나누어서 시도한 크기(총 크기를 500MB로 나눕니다).
    # 여전히 타임아웃을 받으면 작은 크기로 나누어 다시 시도하세요.
    
    git gc
    SIZE=$(git count-objects -v 2> /dev/null | grep size-pack | awk '{print $2}')
    
    # 보수적으로... 2GB씩 푸시를 시도합니다
    # (이것은 각 커밋이 동일한 크기임을 가정했기 때문에 잘못되었습니다)
    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
    

수동으로 내보내기 단계 실행하기

보통 웹 인터페이스 또는 API를 통해 프로젝트를 내보냅니다. 이러한 방법으로 내보내기를 할 때 때로는 충분한 정보 없이 실패할 수 있습니다. 이러한 경우 Rails 콘솔 세션을 열고 정의된 내보내기자를 순회하며 각 줄을 개별적으로 실행하여 각 명령이 반환하는 오류를 볼 수 있도록 합니다.

# 사용자는 내보내기 권한이 있어야 합니다.
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)
e.send(:avatar_saver).send(:save)
e.send(:project_tree_saver).send(:save)
e.send(:uploads_saver).send(:save)
e.send(:wiki_repo_saver).send(:save)
e.send(:lfs_saver).send(:save)
e.send(:snippets_repo_saver).send(:save)
e.send(:design_repo_saver).send(:save)
## 나열된 내보내기자 목록을 통해 `e.send(:exporter_name).send(:save)` 계속 사용

# 다음 라인은 내보내기 경로를 /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, user: u)

# GitLab 17.0 이전에는 `user` 매개변수가 지원되지 않았습니다. 위의 것에 대한 오류가 나타나거나 `user` 매개변수를 제공해야 하는지 확신하지 못하는 경우 다음 확인을 사용하세요.
Gitlab::ImportExport::Saver.instance_method(:initialize).parameters.include?([:keyreq, :user])
# 위의 확인이 false를 반환하면 사용자 매개변수를 생략하세요.
s = Gitlab::ImportExport::Saver.new(exportable: p, shared: p.import_export_shared)

# 시도하려면 다음을 사용하세요:
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를 사용하려면 개인 엑세스 토큰과 같은 일반 사용자 계정 자격 증명을 전달하세요.

오류: PG::QueryCanceled: ERROR: canceling statement due to statement timeout

일부 마이그레이션이 PG::QueryCanceled: ERROR: canceling statement due to statement timeout 오류로 시간 초과될 수 있습니다. 이 문제를 피하는 한 가지 방법은 마이그레이션 일괄 크기를 줄이는 것입니다. 이렇게 하면 마이그레이션이 시간 초과되는 가능성이 줄어들지만 마이그레이션이 느려집니다.

일괄 크기를 줄이려면 기능 플래그를 활성화해야 합니다. 자세한 정보는 이슈 456948을 참조하세요.

오류: command exited with error code 15 and Unable to save [FILTERED] into [FILTERED]

파일 내보내기를 사용하여 프로젝트를 마이그레이션할 때 로그에 command exited with error code 15 and Unable to save [FILTERED] into [FILTERED] 오류가 발생할 수 있습니다. 이 오류를 받으면:

  • 파일 내보내기를 할 때 오류를 무시할 수 있습니다. GitLab은 종료된 명령을 다시 시도합니다.
  • 파일 가져오기시 이 오류를 무시할 수 없습니다. GitLab은 가져오기를 자동으로 다시 시도하지 않습니다.

성능 문제 해결

지금까지의 가이드에서 가져오기/내보내기를 통해 발생하는 현재 성능 문제를 읽어보세요.

OOM 오류

메모리 부족(Out of memory, OOM) 오류는 주로 Sidekiq Memory Killer에 의해 발생합니다:

SIDEKIQ_MEMORY_KILLER_MAX_RSS = 2000000
SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS = 3000000
SIDEKIQ_MEMORY_KILLER_GRACE_TIME = 900

시작된 가져오기 상태 및 다음 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
  +-----------+    +-----------------------------------+
  |내보내기 작업|--->| ActiveRecord에서 `as_json`과 `to_json` 호출하여       |
  +-----------+    | 모든 프로젝트 모델을 메모리로 로드 후       |
                   | DB에 일괄 삽입                          |
                   +-----------------------------------+

  +-----------+    +-----------------------------------+
  |가져오기 작업|--->| 디스크와 SQL에 대한 일괄 읽기/쓰기            |
  +-----------+    +-----------------------------------+

문제와 해결책

문제 가능한 해결책
데이터베이스에서 모델을 느리게 로드/덤프하는 Slow JSON 워커를 분리
  일괄 내보내기
  SQL 최적화
  ActiveRecord 콜백 사용 안 함(어려움)
높은 메모리 사용량(일부 분석도 참고) 덜 메모리를 사용하는 DB 커밋 스위트 스팟
  Netflix Fast JSON API 사용이 도움이 될 수 있음
  디스크 및 SQL에 대한 일괄 읽기/쓰기

임시 해결책

성능 문제를 해결하는 동안, 대형 프로젝트를 가져오기 위한 프로세스를 우회하는 방법이 있습니다. 이를 위해 고객을 대상으로 한 대형 프로젝트의 Foreground Import가 있습니다.