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

migrating projects using file exports에 문제가 있는 경우, 아래 가능한 해결방법을 참조하십시오.

문제 해결 명령

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

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 <기본-브랜치-이름>
    cd ..
    mv project/ ../"$EXPORT"-project
    cd ..
       
    # 가져올 수 있는 파일을 다시 생성합니다
    tar -czf "$EXPORT"-smaller.tar.gz --directory="$EXPORT"/ .
    
  3. 새로운, 더 작은 파일을 GitLab에 가져옵니다.
  4. 원본 리포지터리의 전체 복제에서 git remote set-url origin <새 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 스크립트를 파일로 저장하고 실행하십시오.

    #!/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)를 통해 내보내기 디렉터리을 실행하세요.

내보내기 가능한(p) 및 공유된(p.import_export_shared) 사항을 사용하여, 다음 줄은 다음과 유사한 내보내기 경로를 보여줍니다: /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 오류

메모리 부족(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
막힌 가져오기 작업을 실패로 표시했습니다. JID: xyz
  +-----------+    +-----------------------------------+
  |내보내기 작업|--->| 모든 프로젝트 모델에서 ActiveRecord `as_json` 및  |
  +-----------+    | `to_json`을 호출합니다             |
                   +-----------------------------------+
  
  +-----------+    +-----------------------------------+
  |가져오기 작업|--->| 메모리에 모든 JSON을 로드한 후,   |
  +-----------+    | 일괄적으로 DB에 삽입합니다         |
                   +-----------------------------------+

문제 및 해결책

문제 가능한 해결책
데이터베이스에서 모델을로드/덤프하는 JSON 처리 속도가 느림 작업 분할
  일괄 내보내기
  SQL 최적화
  ActiveRecord 콜백에서 이탈 (어려움)
메모리 사용량이 높음 (일부 분석도 참조) 메모리를 덜 사용하는 DB 커밋 최적 지점
  Netflix Fast JSON API가 도움이 될 수 있음
  디스크로의 일괄적인 읽기/쓰기 및 모든 SQL

임시 해결책

성능 문제가 해결되지 않은 동안, 대형 프로젝트를 가져올 때 대처할 수 있는 프로세스가 있습니다. 대형 프로젝트의 경우 전경 가져오기를 사용하세요. (인프라 트래커의 가져오기 템플릿을 사용합니다: infrastructure tracker)