파일 내보내기 프로젝트 이전의 문제 해결

migrating projects using file exports에 문제가 있다면, 아래 가능한 해결책을 참조하세요.

문제 해결 명령어

JID를 사용하여 가져오기 상태 및 추가 로그에 대한 정보를 찾으려면 Rails console을 사용하세요:

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

일치하지 않아서 프로젝트 가져오기 실패

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

  • 소스 및 대상 프로젝트 모두에서 인스턴스 러너를 활성화합니다.
  • 프로젝트를 가져올 때 부모 그룹에서 인스턴스 러너를 비활성화합니다.

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

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

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

매뉴얼 구성이 불가능할 정도로 많은 사용자가 있다면, Rails console을 사용하여 모든 사용자 프로필을 공개 이메일 주소 사용으로 설정할 수 있습니다:

User.where("public_email IS NULL OR public_email = '' ").find_each do |u|
  next if u.bot?
  
  puts "Setting #{u.username}'s currently empty public email to #{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 브랜치에서 작업하세요: 큰 파일 식별 및 삭제하거나 대화식 리베이스 및 fixup을 사용하여 커밋 수를 줄입니다.

    # .git/objects/pack/ 파일 크기 줄이기
    cd project
    git reflog expire --expire=now --all
    git gc --prune=now --aggressive
       
    # 나중에 가져올 수 있는 파일 생성 준비
    git bundle create ../project.bundle <기본 브랜치 이름>
    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

note
이 회피책은 LFS(Large File Storage) 객체를 고려하지 않습니다.

한꺼번에 모든 변경 사항을 푸시하려고 시도하기보다 다음을 수행하는 이 회피책입니다:

  • 프로젝트 가져오기와 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로 나누어 청크 단위로 푸시하려고 시도합니다.
    # 다시금 제한 시간이 발생하면 크기를 줄여 더 작은 청크로 푸시하세요.
       
    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)

# 업로드를 시도하려면 다음을 사용
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

Import REST API를 사용하려면 개인 액세스 토큰과 같은 일반 사용자 계정 자격 증명을 전달하세요.

성능 문제 해결

다음을 통해 가져오기/내보내기에 대한 현재 성능 문제를 읽어보세요.

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

상태가 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    |
               +-----------------------------------+

문제 및 해결책

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

임시 해결책

성능 문제를 해결하기 전까지, 대형 프로젝트를 가져오는 방법으로 전경 가져오기 프로세스가 있습니다:

대규모 프로젝트를 위한 전경 가져오기 (인프라 트래커의 가져오기 템플릿 사용) .