InfoGrab Docs

Geo 동기화 및 검증 오류 트러블슈팅

요약

Admin > Geo > Sites 또는 동기화 상태 Rake 작업에서 복제 또는 검증 실패가 발생하면 다음 일반 단계를 통해 해결을 시도할 수 있습니다: 수동 재시도를 시도하기 전에 향상된 진단 절차를 사용하여 동기화 문제의 범위와 성격을 더 잘 이해할 수 있습니다.

Admin > Geo > Sites 또는 동기화 상태 Rake 작업에서 복제 또는 검증 실패가 발생하면 다음 일반 단계를 통해 해결을 시도할 수 있습니다:

  1. Geo는 자동으로 실패를 재시도합니다. 실패가 새로 발생했거나 수가 적거나, 근본 원인이 이미 해결됐다고 판단되면 실패가 사라질 때까지 기다릴 수 있습니다.
  2. 실패가 오랫동안 지속됐다면 이미 여러 번 재시도가 발생한 것이며, 자동 재시도 간격이 실패 유형에 따라 최대 4시간으로 늘어납니다. 근본 원인이 이미 해결됐다고 판단되면 수동으로 복제 또는 검증을 재시도하여 대기 시간을 줄일 수 있습니다.
  3. 실패가 지속되면 다음 섹션을 통해 해결을 시도하세요.

진단 절차#

수동 재시도를 시도하기 전에 향상된 진단 절차를 사용하여 동기화 문제의 범위와 성격을 더 잘 이해할 수 있습니다.

모델 상태 확인#

이 절차는 모든 Geo 데이터 유형 모델 클래스에 대한 자세한 상태 정보를 제공하며 체크섬 실패를 식별하는 데 도움이 됩니다. 이러한 실패는 복제 가능 객체의 체크섬을 계산할 수 없을 때 발생합니다. "기본 검증 실패"라고도 합니다.

체크섬 실패는 UI 또는 Rails 콘솔에서 확인할 수 있습니다.

기본 사이트에서 데이터 관리 페이지를 사용하세요.

다음 스크립트를 사용하여 각 모델 유형에 대한 자세한 정보를 출력할 수 있습니다:

  • 레코드 총 수
  • 실패, 검증됨, 대기 중인 레코드 수
  • 조사를 위한 실패 레코드 샘플
Note

ModelMapper 클래스는 GitLab 18.3에서 추가됐습니다. 이전 버전에서는 Geo 데이터 유형 모델 클래스 목록을 수동으로 지정해야 합니다.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 다음 스크립트를 실행하여 포괄적인 개요를 확인하세요:

    def output_geo_verification_failures
      model_classes = ::Gitlab::Geo::ModelMapper.available_models
    
      model_classes.each do |klass|
        total = klass.count
        state_klass = klass.verification_state_table_class
        failed_examples = []
    
        puts "\n=== #{klass.name} ==="
        puts "Total: #{total}"
        ::Geo::VerificationState::VERIFICATION_STATE_VALUES.each do |key, value|
          records = state_klass.where(verification_state: value)
          failed_examples = records if key == 'verification_failed'
    
          puts "#{key.gsub('verification_', '').camelize}: #{records.size}"
        end
    
        if failed_examples.any?
          puts "\nSample failed records:"
          failed_examples.limit(3).each { |record| puts "  ID: #{record.id}, Checksum: #{record.verification_checksum || 'nil'}, Error: #{record.verification_failure}" }
        end
      end
    
      nil
    end
    
    output_geo_verification_failures
    

레지스트리 상태 확인#

이 절차는 모든 Geo 레지스트리 유형에 대한 자세한 상태 정보를 제공하며 실패 패턴을 식별하는 데 도움이 됩니다.

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 다음 스크립트를 실행하여 포괄적인 개요를 확인하세요:

    def output_geo_failures()
      registry_classes = [
        Geo::UploadRegistry,
        Geo::JobArtifactRegistry,
        Geo::PackageFileRegistry,
        Geo::PagesDeploymentRegistry,
        Geo::ProjectRepositoryRegistry,
        Geo::TerraformStateVersionRegistry,
        Geo::MergeRequestDiffRegistry,
        Geo::LfsObjectRegistry,
        Geo::PipelineArtifactRegistry,
        Geo::CiSecureFileRegistry
      ]
    
      registry_classes.each do |klass|
        puts "\n=== #{klass.name} ==="
        puts "Total: #{klass.count}"
        puts "Failed: #{klass.failed.count}"
        puts "Synced: #{klass.synced.count}"
        puts "Pending: #{klass.pending.count}"
        puts "Started: #{klass.with_state(:started).count}"
    
        if klass.failed.count > 0
           puts "\nSample failed records:"
           klass.failed.limit(3).each { |record| puts "  ID: #{record.id}, Error: #{record.last_sync_failure}" }
        end
      end
    
      nil
    end
    
    output_geo_failures()
    
  3. 이 스크립트는 각 레지스트리 유형에 대한 자세한 정보를 출력합니다:

    • 레코드 총 수
    • 실패, 동기화됨, 대기 중인 레코드 수
    • 조사를 위한 실패 레코드 샘플

복제 또는 검증 수동 재시도#

보조 Geo 사이트의 Rails 콘솔에서 다음을 수행할 수 있습니다:

개별 컴포넌트 재동기화 및 재검증#

보조 사이트에서 Admin > Geo > Replication으로 이동하여 개별 항목을 강제로 재동기화하거나 재검증할 수 있습니다.

그러나 이 방법이 작동하지 않는 경우 Rails 콘솔을 사용하여 동일한 작업을 수행할 수 있습니다. 다음 섹션에서는 Rails 콘솔의 내부 애플리케이션 명령을 사용하여 개별 레코드에 대한 복제 또는 검증을 동기적 또는 비동기적으로 유발하는 방법을 설명합니다.

Replicator 인스턴스 획득#

Warning

데이터를 변경하는 명령은 올바르게 실행되지 않거나 올바른 조건에서 실행되지 않으면 손상을 일으킬 수 있습니다. 항상 먼저 테스트 환경에서 명령을 실행하고 복원 준비가 된 백업 인스턴스를 마련하세요.

동기화 또는 검증 작업을 수행하기 전에 Replicator 인스턴스를 획득해야 합니다.

먼저, 수행하려는 작업에 따라 기본 또는 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

기본 사이트에서:

  • 리소스를 체크섬할 수 있습니다.

보조 사이트에서:

  • 리소스를 동기화할 수 있습니다.
  • 리소스를 체크섬하고 해당 체크섬을 기본 사이트의 체크섬과 비교하여 검증할 수 있습니다.

다음으로, 다음 스니펫 중 하나를 실행하여 Replicator 인스턴스를 가져옵니다.

모델 레코드의 ID로 가져오기#
model_record = Packages::PackageFile.find_by(id: 123)
replicator = model_record.replicator
레지스트리 레코드의 ID로 가져오기#
  • 432를 실제 ID로 교체하세요. 레지스트리 레코드는 추적하는 모델 레코드와 동일한 ID 값을 가질 수도 있고 그렇지 않을 수도 있습니다.
  • Geo::PackageFileRegistryGeo 레지스트리 클래스 중 하나로 교체하세요.

보조 Geo 사이트에서:

registry_record = Geo::PackageFileRegistry.find_by(id: 432)
replicator = registry_record.replicator
레지스트리 레코드의 last_sync_failure에 있는 오류 메시지로 가져오기#
  • Geo::PackageFileRegistryGeo 레지스트리 클래스 중 하나로 교체하세요.
  • error message here를 실제 오류 메시지로 교체하세요.
registry = Geo::PackageFileRegistry.find_by("last_sync_failure LIKE '%error message here%'")
replicator = registry.replicator
레지스트리 레코드의 verification_failure에 있는 오류 메시지로 가져오기#
  • Geo::PackageFileRegistryGeo 레지스트리 클래스 중 하나로 교체하세요.
  • error message here를 실제 오류 메시지로 교체하세요.
registry = Geo::PackageFileRegistry.find_by("verification_failure LIKE '%error message here%'")
replicator = registry.replicator

Replicator 인스턴스로 작업 수행#

replicator 변수에 Replicator 인스턴스를 저장한 후 여러 작업을 수행할 수 있습니다:

콘솔에서 동기화#

이 스니펫은 보조 사이트에서만 작동합니다.

이는 콘솔에서 동기화 코드를 동기적으로 실행하므로 리소스 동기화에 얼마나 걸리는지 관찰하거나 전체 오류 백트레이스를 볼 수 있습니다.

replicator.sync

선택적으로, 콘솔의 로그 수준을 설정된 로그 수준보다 더 자세하게 만든 다음 동기화를 수행하세요:

Rails.logger.level = :debug
콘솔에서 체크섬 또는 검증#

이 스니펫은 모든 기본 또는 보조 사이트에서 작동합니다.

기본 사이트에서는 리소스를 체크섬하고 결과를 메인 GitLab 데이터베이스에 저장합니다. 보조 사이트에서는 리소스를 체크섬하고 메인 GitLab 데이터베이스의 체크섬(기본 사이트에서 생성된)과 비교하여 결과를 Geo 추적 데이터베이스에 저장합니다.

이는 콘솔에서 체크섬 및 검증 코드를 동기적으로 실행하므로 얼마나 걸리는지 관찰하거나 전체 오류 백트레이스를 볼 수 있습니다.

replicator.verify
Sidekiq 작업에서 동기화#

이 스니펫은 보조 사이트에서만 작동합니다.

리소스의 동기화를 수행하기 위해 Sidekiq 작업을 큐에 넣습니다.

replicator.enqueue_sync
Sidekiq 작업에서 검증#

이 스니펫은 모든 기본 또는 보조 사이트에서 작동합니다.

리소스의 체크섬 또는 검증을 수행하기 위해 Sidekiq 작업을 큐에 넣습니다.

replicator.verify_async
모델 레코드 가져오기#

이 스니펫은 모든 기본 또는 보조 사이트에서 작동합니다.

replicator.model_record
레지스트리 레코드 가져오기#

이 스니펫은 레지스트리 테이블이 Geo 추적 DB에 저장되므로 보조 사이트에서만 작동합니다.

replicator.registry

Geo 데이터 유형 모델 클래스#

Geo 데이터 유형은 하나 이상의 GitLab 기능에 필요한 데이터를 저장하고 Geo에 의해 보조 사이트로 복제되는 특정 데이터 클래스입니다.

  • Blob 유형:
    • Ci::JobArtifact
    • Ci::PipelineArtifact
    • Ci::SecureFile
    • LfsObject
    • MergeRequestDiff
    • Packages::PackageFile
    • PagesDeployment
    • Terraform::StateVersion
    • Upload
    • DependencyProxy::Manifest
    • DependencyProxy::Blob
  • Git 저장소 유형:
    • DesignManagement::Repository
    • ProjectRepository
    • ProjectWikiRepository
    • SnippetRepository
    • GroupWikiRepository
  • 기타 유형:
    • ContainerRepository

주요 클래스 종류는 Registry, Model, Replicator입니다. 이 클래스 중 하나의 인스턴스가 있으면 다른 것을 가져올 수 있습니다. Registry와 Model은 주로 PostgreSQL DB 상태를 관리합니다. Replicator는 PostgreSQL 외 데이터(파일/Git 저장소/컨테이너 저장소)를 복제하거나 검증하는 방법을 알고 있습니다.

Geo 레지스트리 클래스#

GitLab Geo의 맥락에서 레지스트리 레코드는 Geo 추적 데이터베이스의 레지스트리 테이블을 가리킵니다. 각 레코드는 LFS 파일이나 프로젝트 Git 저장소와 같이 메인 GitLab 데이터베이스의 단일 복제 가능 항목을 추적합니다. 쿼리할 수 있는 Geo 레지스트리 테이블에 해당하는 Rails 모델은:

  • Blob 유형:
    • Geo::CiSecureFileRegistry
    • Geo::DependencyProxyBlobRegistry
    • Geo::DependencyProxyManifestRegistry
    • Geo::JobArtifactRegistry
    • Geo::LfsObjectRegistry
    • Geo::MergeRequestDiffRegistry
    • Geo::PackageFileRegistry
    • Geo::PagesDeploymentRegistry
    • Geo::PipelineArtifactRegistry
    • Geo::ProjectWikiRepositoryRegistry
    • Geo::SnippetRepositoryRegistry
    • Geo::TerraformStateVersionRegistry
    • Geo::UploadRegistry
  • Git 저장소 유형:
    • Geo::DesignManagementRepositoryRegistry
    • Geo::ProjectRepositoryRegistry
    • Geo::ProjectWikiRepositoryRegistry
    • Geo::SnippetRepositoryRegistry
    • Geo::GroupWikiRepositoryRegistry
  • 기타 유형:
    • Geo::ContainerRepositoryRegistry

여러 컴포넌트 재동기화 및 재검증#

히스토리
  • 대량 재동기화 및 재검증 기능이 GitLab 16.5에서 추가됨.

컴포넌트 리소스 동기화 또는 검증에 실패하면 대량 작업을 트리거하여 복제 큐를 다시 시작할 수 있습니다. 이러한 작업은 재시도 횟수와 예약 시간을 0으로 재설정하여 시스템이 최대 1시간을 기다리지 않고 더 빨리 실패한 리소스를 처리하도록 합니다.

Note

이러한 작업은 리소스를 즉시 처리하지 않습니다. 대신 동기화 및 검증을 처리하는 백그라운드 작업을 다시 큐에 넣습니다. 실제 복제 작업은 표준 Geo 복제 프로세스를 통해 비동기적으로 발생합니다.

재동기화 및 재검증 작동 방식#

재동기화 또는 재검증 작업을 트리거하면 시스템은 일치하는 레코드를 pending으로 표시합니다. Geo 재동기화 및 재검증 백그라운드 워커가 이러한 레코드를 선택하고 일반 큐 우선 순위에 따라 처리합니다. 이 메커니즘을 사용하면 작업을 즉시 차단하지 않고 실패한 리소스 처리를 앞당길 수 있습니다.

Note

성공적으로 동기화되지 않은 레코드는 재검증할 수 없습니다. 동기화된 레코드만 검증할 수 있습니다.

UI 또는 Rails 콘솔에서 대량 작업을 트리거할 수 있습니다.

UI에서#

UI에서 한 컴포넌트의 모든 리소스에 대한 전체 재동기화를 예약할 수 있습니다:

  1. 오른쪽 상단에서 Admin을 선택합니다.
  2. 왼쪽 사이드바에서 Geo > Sites를 선택합니다.
  3. Replication details 아래에서 원하는 컴포넌트를 선택합니다.
선택한 컴포넌트에 대한 리소스 재동기화#
  1. Resync all 선택: 이미 동기화됐는지 여부에 관계없이 선택한 리소스의 모든 레코드 상태를 재설정합니다.
  2. Resync all failed 선택: 동기화에 실패한 모든 레코드를 재설정합니다.
선택한 컴포넌트에 대한 리소스 재검증#
  1. Reverify all 선택: 이미 검증됐는지 여부에 관계없이 선택한 리소스의 모든 레코드 상태를 재설정합니다.
  2. Reverify all failed 선택: 검증에 실패했지만 동기화에 성공한 모든 레코드를 재설정합니다.
모든 사이트에서 하나의 컴포넌트 재검증#

기본 사이트의 체크섬에 의문이 있는 경우 기본 사이트가 체크섬을 다시 계산하도록 해야 합니다. 이후 기본 사이트에서 각 체크섬이 재계산된 후 이벤트가 생성되어 모든 보조 사이트로 전파되고 체크섬을 재계산하여 값을 비교합니다. 불일치가 발생하면 레지스트리를 sync failed로 표시하여 동기화 재시도가 예약됩니다.

UI에서 기본 사이트의 체크섬을 재계산할 수 있습니다:

  1. 오른쪽 상단에서 Admin을 선택합니다.
  2. 왼쪽 사이드바에서 Monitoring > Data management를 선택합니다.
  3. 드롭다운 목록에서 원하는 컴포넌트를 선택합니다.
  4. Checksum all을 선택합니다.
Warning

Resync all, Reverify all, Checksum all은 이미 동기화되거나 검증된 여부에 관계없이 모든 리소스의 업데이트를 트리거합니다. 인스턴스에 특정 객체 유형이 수천 개 있는 경우(예: CI Job Artifacts) 실행하지 마세요.

Rails 콘솔에서#

Warning

데이터를 변경하는 명령은 올바르게 실행되지 않거나 올바른 조건에서 실행되지 않으면 손상을 일으킬 수 있습니다. 항상 먼저 테스트 환경에서 명령을 실행하고 복원 준비가 된 백업 인스턴스를 마련하세요.

다음 섹션에서는 Rails 콘솔의 내부 애플리케이션 명령을 사용하여 대량 복제 또는 검증을 유발하는 방법을 설명합니다.

동기화에 실패한 하나의 컴포넌트의 모든 리소스 동기화#

다음 스크립트:

  • 모든 실패한 저장소를 반복합니다.
  • 마지막 실패 이유를 포함한 Geo 동기화 및 검증 메타데이터를 표시합니다.
  • 저장소를 다시 동기화하려고 시도합니다.
  • 실패가 발생하면 이유와 함께 보고합니다.
  • 완료하는 데 시간이 걸릴 수 있습니다. 결과를 보고하기 전에 각 저장소 검사가 완료되어야 합니다. 세션이 시간 초과되면 screen 세션을 시작하거나 Rails runnernohup을 사용하여 프로세스가 계속 실행되도록 조치를 취하세요.

보조 Geo 사이트에서 이 스크립트를 실행하세요.

Geo::ProjectRepositoryRegistry.failed.find_each do |registry|
   begin
     puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Last Sync Failure: '#{registry.last_sync_failure}'"
     registry.replicator.sync
     puts "Sync initiated for registry ID: #{registry.id}"
   rescue => e
     puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Failed: '#{e}'", e.backtrace.join("\n")
   end
end; nil
기본 사이트에서 체크섬에 실패한 모든 리소스 재검증#

시스템은 기본 사이트에서 체크섬에 실패한 모든 리소스를 자동으로 재검증하지만, 과도한 양의 실패를 방지하기 위해 점진적 백오프 방식을 사용합니다.

선택적으로, 예를 들어 개입 시도를 완료한 경우 더 빨리 재검증을 수동으로 트리거할 수 있습니다:

  1. 기본 사이트의 GitLab Rails 노드에 SSH로 로그인합니다.

  2. Rails 콘솔을 엽니다.

  3. UploadGeo 데이터 유형 모델 클래스 중 하나로 교체하여 모든 리소스를 pending verification으로 표시합니다:

    Upload.verification_state_table_class.where(verification_state: 3).each_batch do |relation|
      relation.update_all(verification_state: 0)
    end
    

오류#

메시지: The file is missing on the Geo primary site#

동기화 실패 The file is missing on the Geo primary site는 처음 보조 Geo 사이트를 설정할 때 기본 사이트의 데이터 불일치로 인해 일반적으로 발생합니다.

데이터 불일치와 파일 누락은 GitLab을 운영하면서 시스템 또는 인적 오류로 인해 발생할 수 있습니다. 예를 들어, 인스턴스 관리자가 로컬 파일 시스템에서 여러 아티팩트를 수동으로 삭제합니다. 이러한 변경 사항은 데이터베이스에 제대로 전파되지 않아 불일치가 발생합니다. 이러한 불일치는 유지되어 마찰을 일으킬 수 있습니다. Geo 보조 사이트는 데이터베이스에 여전히 참조되지만 더 이상 존재하지 않는 파일들을 계속 복제하려고 시도할 수 있습니다.

Note

최근 로컬에서 오브젝트 스토리지로 마이그레이션한 경우 전용 오브젝트 스토리지 트러블슈팅 섹션을 참조하세요.

불일치 식별#

이 오류를 조사하려면 불일치 가능한 내용을 찾아야 합니다. 불일치는 Admin > Geo > Sites의 동기화 상태 또는 UI의 다른 곳에서 확인할 수 있습니다.

기본 사이트에서 데이터 관리 페이지를 사용하세요.

누락된 파일 또는 불일치가 있을 때 다음과 같은 항목이 geo.log에 나타날 수 있습니다. "primary_missing_file" : true 필드에 주목하세요:

{
   "bytes_downloaded" : 0,
   "class" : "Geo::BlobDownloadService",
   "correlation_id" : "01JT69C1ECRBEMZHA60E5SAX8E",
   "download_success" : false,
   "download_time_s" : 0.196,
   "gitlab_host" : "gitlab.example.com",
   "mark_as_synced" : false,
   "message" : "Blob download",
   "model_record_id" : 55,
   "primary_missing_file" : true,
   "reason" : "Not Found",
   "replicable_name" : "upload",
   "severity" : "WARN",
   "status_code" : 404,
   "time" : "2025-05-01T16:02:44.836Z",
   "url" : "http://gitlab.example.com/api/v4/geo/retrieve/upload/55"
}

동일한 오류는 특정 복제 가능 항목의 동기화 상태를 검토할 때 Admin > Geo > Sites의 UI에도 반영됩니다. 이 시나리오에서는 특정 업로드가 누락됩니다:

모든 실패 오류를 표시하는 Geo Uploads 복제 가능 대시보드.

누락된 파일 오류를 표시하는 Geo Uploads 복제 가능 대시보드.

불일치 정리#

Warning

삭제 명령을 실행하기 전에 최근의 작동하는 백업이 있는지 확인하세요.

이러한 오류를 제거하려면 먼저 어떤 특정 리소스가 영향을 받는지 식별하세요. 그런 다음 적절한 destroy 명령을 실행하여 삭제가 모든 Geo 사이트와 해당 데이터베이스에 전파되도록 합니다. 이전 시나리오를 기반으로 업로드가 이러한 오류를 일으키고 있으며 아래 예제로 사용됩니다.

  1. 식별된 불일치를 해당 Geo 모델 클래스 이름에 매핑합니다. 클래스 이름은 다음 단계에서 필요합니다. 이 시나리오에서 업로드의 경우 Upload에 해당합니다.

  2. Geo 기본 사이트에서 Rails 콘솔을 시작합니다.

  3. 이전 단계의 Geo 모델 클래스를 기반으로 누락된 파일로 인해 검증이 실패한 모든 리소스를 쿼리합니다. limit(20)을 조정하거나 제거하여 더 많은 결과를 표시합니다. 나열된 리소스가 UI에 표시된 실패한 리소스와 일치해야 함을 확인하세요:

    Upload.verification_failed.where("verification_failure like '%File is not checksummable%'").limit(20)
    
    => #
    
  4. 선택적으로, 영향받은 리소스의 id를 사용하여 아직 필요한지 확인합니다:

    Upload.find(55)
    
    => #
    
    • 영향받은 리소스를 복구해야 한다고 판단되면 다음 옵션(비망라적)을 탐색하여 복구할 수 있습니다:
      • 보조 사이트에 오브젝트가 있는지 확인하고 기본 사이트로 수동으로 복사합니다.
      • 이전 백업을 통해 오브젝트를 기본 사이트로 수동으로 다시 복사합니다.
      • 몇 가지를 샘플로 확인하여 레코드를 삭제하는 것이 괜찮다고 판단합니다. 예를 들어 모두 매우 오래된 아티팩트라면 중요한 데이터가 아닐 수 있습니다.
  5. 식별된 리소스의 id를 사용하여 destroy로 개별 또는 대량으로 적절히 삭제합니다. 적절한 Geo 모델 클래스 이름을 사용하세요.

    • 개별 리소스 삭제:

      Upload.find(55).destroy
      
    • 영향받은 모든 리소스 삭제:

      def destroy_uploads_not_checksummable
        uploads = Upload.verification_failed.where("verification_failure like '%File is not checksummable%'");1
        puts "Found #{uploads.count} resources that failed verification with 'File is not checksummable'."
        puts "Enter 'y' to continue: "
        prompt = STDIN.gets.chomp
        if prompt != 'y'
          puts "Exiting without action..."
          return
        end
      
        puts "Destroying all..."
        uploads.destroy_all
      end
      
      destroy_uploads_not_checksummable
      

모든 영향받은 리소스와 Geo 데이터 유형에 대해 단계를 반복합니다.

메시지: "Error during verification","error":"File is not checksummable"#

오류 "Error during verification","error":"File is not checksummable"는 기본 사이트의 불일치로 인해 발생합니다. GitLab 18.9부터 오류 메시지에 원인에 대한 추가 세부 정보가 포함됩니다:

  • File is not checksummable - file does not exist at: <path>: 파일이 스토리지에 없습니다. 표시된 경로가 누락된 파일을 식별하는 데 도움이 됩니다.
  • File is not checksummable - is excluded from verification: 레코드가 검증 범위에서 제외됩니다.

Geo 기본 사이트에서 파일 누락에 제공된 지침을 따르세요.

기본 Geo 사이트에서 업로드 검증 실패#

verification_checksum = nil이고 verification_failureError during verification: undefined method `underscore' for NilClass:Class 또는 The model which owns this Upload is missing.가 포함된 경우 기본 Geo 사이트에서 일부 업로드 검증이 실패하는 것은 고아 업로드(orphaned Uploads)로 인한 것입니다. 업로드를 소유하는 상위 레코드(업로드의 "모델")가 어떤 이유로 삭제됐지만 Upload 레코드는 여전히 존재합니다. 이는 일반적으로 "모델"의 대량 삭제를 구현하면서 연관된 Upload 레코드의 대량 삭제를 잊어버리는 애플리케이션 버그로 인한 것입니다. 따라서 이러한 검증 실패는 실제 검증 실패가 아니라 Postgres의 잘못된 데이터로 인한 오류입니다.

기본 Geo 사이트geo.log 파일에서 이러한 오류를 찾을 수 있습니다.

모델 레코드가 누락됐는지 확인하려면 기본 Geo 사이트에서 Rake 작업을 실행할 수 있습니다:

sudo gitlab-rake gitlab:uploads:check

Rails 콘솔에서 다음 스크립트를 실행하여 기본 Geo 사이트에서 이러한 Upload 레코드를 삭제하고 이러한 실패를 제거할 수 있습니다:

def delete_orphaned_uploads(dry_run: true)
  if dry_run
    p "This is a dry run. Upload rows will only be printed."
  else
    p "This is NOT A DRY RUN! Upload rows will be deleted from the DB!"
  end

  subquery = Geo::UploadState.where("(verification_failure LIKE 'Error during verification: The model which owns this Upload is missing.%' OR verification_failure = 'Error during verification: undefined method `underscore'' for NilClass:Class') AND verification_checksum IS NULL")
  uploads = Upload.where(upload_state: subquery)
  p "Found #{uploads.count} uploads with a model that does not exist"

  uploads_deleted = 0
  begin
    uploads.each do |upload|

      if dry_run
        p upload
      else
        uploads_deleted=uploads_deleted + 1
        p upload.destroy!
      end
    rescue => e
      puts "checking upload #{upload.id} failed with #{e.message}"
    end
  end

  p "#{uploads_deleted} remote objects were destroyed." unless dry_run
end

이전 스크립트는 delete_orphaned_uploads라는 메서드를 정의합니다. 드라이 런을 수행하려면 다음과 같이 호출합니다:

delete_orphaned_uploads(dry_run: true)

실제로 고아 업로드 행을 삭제하려면:

delete_orphaned_uploads(dry_run: false)

저장소 동기화를 차단하는 고아 전용 임대 키#

전용 임대 키가 고아가 되면 저장소 동기화가 차단되어 최대 8시간 동안 동기화 작업이 방지될 수 있습니다.

증상:

  • 저장소 동기화 차단: 영향받은 저장소의 복제 상태가 pendingfailed 상태 사이를 왔다갔다합니다.
  • geo.log에서 "Cannot obtain an exclusive lease" 메시지가 있는 로그 라인이 증가합니다.
  • 영향받은 저장소에 대해 활성 동기화 작업이 실행되지 않습니다.
  • 임대가 만료될 때까지 최대 8시간 동안 단일 저장소에 영향을 미칩니다.

진단:

  1. Geo 관리자 인터페이스를 확인하여 저장소가 활성 동기화 중이 아님을 확인합니다.

  2. geo.log에서 "Cannot obtain an exclusive lease" 메시지 수가 증가했는지 확인합니다:

    grep "Cannot obtain an exclusive lease" /var/log/gitlab/geo/geo.log
    
  3. 이러한 모든 로그 라인에 geo_sync_ssf_service:project_repository:<repository id> 값의 lease_key 필드가 포함되는지 확인합니다. 여기서 <repository id>는 영향받은 저장소의 고유 ID입니다.

  4. Sidekiq에서 영향받은 저장소에 대한 활성 동기화 작업이 실행 중이 아님을 확인합니다.

해결 방법:

Warning

권장 접근 방식은 8시간 임대 만료를 기다리는 것입니다. 수동 임대 해제는 활성 동기화 작업이 실행되지 않음을 확인했고 즉각적인 동기화가 중요한 경우에만 사용해야 합니다.

고아 임대 키를 수동으로 해제하려면:

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 영향받은 저장소의 프로젝트 ID를 찾습니다(<project-path>를 실제 프로젝트 경로로 교체):

    project = Project.find_by_full_path('<project-path>')
    project_id = project.id
    
  3. 동일한 세션에서 고아 임대를 해제합니다:

    replicator = Geo::ProjectRepositoryRegistry.find_by(project_id: project_id).replicator
    sync_service = Geo::FrameworkRepositorySyncService.new(replicator)
    uuid = Gitlab::ExclusiveLease.get_uuid(sync_service.lease_key)
    
    if uuid
      Gitlab::ExclusiveLease.cancel(sync_service.lease_key, uuid)
      puts "Lease released for project ID #{project_id}"
    else
      puts "No active lease found for project ID #{project_id}"
    end
    
  4. 임대가 해제됐는지 확인하고 새 동기화를 트리거합니다:

    replicator.sync
    
Note

임대 해제 후 저장소 동기화는 일반 Geo 동기화 일정에 따라 재시도됩니다. 또는 위와 같이 동기화를 수동으로 트리거할 수 있습니다.

오류: Error syncing repository: 13:fatal: could not read Username#

last_sync_failure 오류 Error syncing repository: 13:fatal: could not read Username for 'https://gitlab.example.com': terminal prompts disabled는 Geo 클론 또는 페치 요청 중에 JWT 인증이 실패하고 있음을 나타냅니다.

먼저 시스템 시계가 동기화됐는지 확인합니다. 상태 확인 Rake 작업을 실행하거나 보조 사이트의 모든 Sidekiq 노드와 기본 사이트의 모든 Puma 노드에서 date가 동일한지 수동으로 확인합니다.

시스템 시계가 동기화됐다면 JWT 토큰이 Git 페치가 두 개의 별도 HTTP 요청 사이에 계산을 수행하는 동안 만료될 수 있습니다. GitLab 17.1.0, 17.0.5, 16.11.7에서 수정될 때까지 모든 GitLab 버전에 존재했던 이슈 464101을 참조하세요.

이 문제를 경험하고 있는지 확인하려면:

  1. Rails 콘솔에서 코드를 몽키 패치하여 토큰 유효 기간을 1분에서 10분으로 늘립니다. 보조 사이트의 Rails 콘솔에서 실행합니다:

    module Gitlab; module Geo; class BaseRequest
      private
      def geo_auth_token(message)
        signed_data = Gitlab::Geo::SignedData.new(geo_node: requesting_node, validity_period: 10.minutes).sign_and_encode_data(message)
    
        "#{GITLAB_GEO_AUTH_TOKEN_TYPE} #{signed_data}"
      end
    end;end;end
    
  2. 동일한 Rails 콘솔에서 영향받은 프로젝트를 재동기화합니다:

    Project.find_by_full_path('<mygroup/mysubgroup/myproject>').replicator.resync
    
  3. 동기화 상태를 확인합니다:

    Project.find_by_full_path('<mygroup/mysubgroup/myproject>').replicator.registry
    
  4. last_sync_failure에 더 이상 fatal: could not read Username 오류가 포함되지 않으면 이 문제의 영향을 받고 있는 것입니다. 상태가 이제 2이어야 하며, 이는 동기화됐다는 것을 의미합니다. 그렇다면 수정이 포함된 GitLab 버전으로 업그레이드해야 합니다. 이 문제의 심각성을 줄일 수 있었을 이슈 466681에 투표하거나 댓글을 달 수도 있습니다.

이 문제를 해결하려면 보조 사이트의 모든 Sidekiq 노드를 핫 패치하여 JWT 만료 시간을 연장해야 합니다:

  1. /opt/gitlab/embedded/service/gitlab-rails/ee/lib/gitlab/geo/signed_data.rb를 편집합니다.

  2. Gitlab::Geo::SignedData.new(geo_node: requesting_node)를 찾아 , validity_period: 10.minutes를 추가합니다:

    - Gitlab::Geo::SignedData.new(geo_node: requesting_node)
    + Gitlab::Geo::SignedData.new(geo_node: requesting_node, validity_period: 10.minutes)
    
  3. Sidekiq를 재시작합니다:

    sudo gitlab-ctl restart sidekiq
    
  4. 수정이 포함된 버전으로 업그레이드하지 않는 한 모든 GitLab 업그레이드 후에 이 해결 방법을 반복해야 합니다.

오류: Error syncing repository: 13:creating repository: cloning repository: exit status 128#

성공적으로 동기화되지 않는 프로젝트에서 이 오류가 발생할 수 있습니다.

저장소 생성 중 종료 코드 128은 Git이 클론하는 동안 치명적인 오류를 발생시켰음을 의미합니다. 이는 저장소 손상, 네트워크 문제, 인증 문제, 리소스 한계 또는 프로젝트에 연관된 Git 저장소가 없어서 발생할 수 있습니다. 이러한 실패의 구체적인 원인에 대한 자세한 내용은 Gitaly 로그에서 찾을 수 있습니다.

시작 위치가 불확실한 경우 커맨드 라인에서 git fsck 명령을 수동으로 실행하여 기본 사이트의 소스 저장소에 대한 무결성 검사를 실행합니다.

오류: gitmodulesUrl: disallowed submodule url#

일부 프로젝트 저장소가 Error syncing repository: 13:creating repository: cloning repository: exit status 128 오류로 지속적으로 동기화에 실패합니다. 그러나 일부 저장소의 경우 Gitaly 로그의 구체적인 오류 메시지가 다릅니다: gitmodulesUrl: disallowed submodule url. 이 실패는 저장소에 .gitmodules 파일에 잘못된 서브모듈 URL이 포함될 때 발생합니다.

근본 원인: 이 문제는 .gitmodules 파일에 잘못된 형식의 URL이 포함된 Git 저장소의 이전 커밋으로 인해 발생합니다. 이 문제는 Geo가 기본 사이트에서 보조 사이트로 저장소를 클론하려고 할 때 실행되는 Git의 일관성 검사(git fsck) 중에 발생합니다.

문제는 저장소의 커밋 히스토리에 있습니다. .gitmodules 파일의 서브모듈 URL에 경로에 / 대신 : 를 사용하는 잘못된 형식이 포함됩니다:

  • 잘못된 형식: https://example.gitlab.com:group/project.git
  • 올바른 형식: https://example.gitlab.com/group/project.git

Geo 동기화가 실패하는 이유:

  1. Git의 엄격한 유효성 검사: GitLab 17.0 및 최신 Git 버전부터 Git은 클론 작업 중에 더 엄격한 fsck 검사를 수행합니다.
  2. 이전 데이터 유지: 현재 .gitmodules 파일이 올바르더라도 Git은 모든 이전 버전을 저장소의 "Blob"으로 저장합니다.
  3. 클론 시 실패: Geo가 저장소를 클론하려고 할 때 Git의 fsck모든 오브젝트(이전 것 포함)를 검사하고 잘못된 형식의 URL을 발견하면 실패합니다.
  4. 완전한 동기화 실패: 전체 클론 작업이 실패하여 저장소가 보조 사이트에 도달하지 못하게 됩니다.

중요: 현재 .gitmodules 파일을 편집해도 이 문제가 해결되지 않습니다. 왜냐하면 문제가 있는 데이터는 파일의 현재 버전이 아닌 저장소의 Git 히스토리에 존재하기 때문입니다.

이 문제는 GitLab 17.0 이상에서 알려져 있으며, 더 엄격한 저장소 일관성 검사의 결과입니다. 이 새로운 동작은 이 검사가 추가된 Git 자체의 변경으로 인한 것입니다. GitLab Geo 또는 Gitaly에 국한된 것이 아닙니다. 자세한 내용은 이슈 468560을 참조하세요.

해결 방법#

  1. 프로젝트 백업

    계속하기 전에 프로젝트 내보내기 옵션을 사용하여 프로젝트를 미리 백업하세요.

  2. 문제가 있는 Blob ID 식별

    영향받은 각 프로젝트에 대해 다음 방법 중 하나를 사용하여 문제가 있는 Blob ID를 식별합니다:

    • git fsck 사용: 저장소를 클론한 후 git fsck를 실행하여 문제를 확인합니다:

      git clone https://example.gitlab.com/group/project.git
      cd project
      git fsck
      

      출력은 문제가 있는 Blob을 보여줍니다:

      Checking object directories: 100% (256/256), done.
      error in blob : gitmodulesUrl: disallowed submodule url: https://example.gitlab.com:group/project.git
      Checking objects: 100% (12/12), done.
      
    • Gitaly 로그를 확인합니다. 특정 Blob SHA를 찾기 위해 gitmodulesUrl이 포함된 오류 메시지를 찾습니다.

  3. Blob 제거

    영향받은 각 프로젝트에 대해 이전 단계에서 식별된 문제가 있는 Blob ID를 제거합니다.

    중요한 제한 사항: 이러한 저장소 중 하나라도 포크 네트워크의 일부라면 Blob 제거 방법이 작동하지 않을 수 있습니다(오브젝트 풀에 포함된 Blob은 이 방법으로 제거할 수 없음).

  4. 필요한 경우 .gitmodules 잘못된 URL 수정

    영향받은 각 저장소의 .gitmodules 파일 상태를 확인합니다.

    .gitmodules에 여전히 https://example.gitlab.com/foo/bar.git 대신 https://example.gitlab.com:foo/bar.git와 같은 잘못된 URL이 포함되어 있으면:

    • .gitmodules 파일에서 URL을 수정합니다.
    • 유효한 URL로 커밋을 푸시합니다.
Warning

수정 후, 영향받은 프로젝트에서 작업하는 모든 개발자는 현재 로컬 복사본을 제거하고 새 저장소를 클론해야 합니다. 그렇지 않으면 변경 사항을 푸시할 때 문제가 있는 Blob을 다시 도입할 수 있습니다.

오류: 정확히 3시간에 fetch remote: signal: terminated: context deadline exceeded#

Git 저장소를 동기화하는 동안 정확히 3시간에 Git 페치가 실패하는 경우:

  1. /etc/gitlab/gitlab.rb를 편집하여 기본값 10800초에서 Git 시간 초과를 늘립니다:

    # Git timeout in seconds
    gitlab_rails['gitlab_shell_git_timeout'] = 21600
    
  2. GitLab을 재구성합니다:

    sudo gitlab-ctl reconfigure
    

보조 사이트에서 레지스트리 복제 구성 시 오류 Failed to open TCP connection to localhost:5000#

보조 사이트에서 컨테이너 레지스트리 복제를 구성할 때 다음 오류가 발생할 수 있습니다:

Failed to open TCP connection to localhost:5000 (Connection refused - connect(2) for \"localhost\" port 5000)"

보조 사이트에서 컨테이너 레지스트리가 활성화되지 않은 경우 이 문제가 발생합니다. 이를 수정하려면 컨테이너 레지스트리가 보조 사이트에서 활성화됐는지 확인합니다. Let's Encrypt 통합이 비활성화된 경우 컨테이너 레지스트리도 비활성화되므로 자체 도메인에서 수동으로 구성해야 합니다.

오류: Verification timed out after 28800#

가능한 근본 원인: 다양한 레지스트리 유형에서 검증 충돌을 일으키는 중복 레지스트리 레코드.

진단:

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 여러 유형에서 중복 레지스트리를 확인합니다:

    # Check for duplicate upload registries
    upload_ids = Geo::UploadRegistry.group(:file_id).having('COUNT(*) > 1').pluck(:file_id)
    puts "Duplicate upload IDs count: #{upload_ids.size}"
    puts 'Duplicate Upload IDs:', upload_ids
    
    # Check for duplicate job artifact registries
    artifact_ids = Geo::JobArtifactRegistry.group(:artifact_id).having('COUNT(*) > 1').pluck(:artifact_id)
    puts "Duplicate artifact IDs count: #{artifact_ids.size}"
    puts 'Duplicate Artifact IDs:', artifact_ids
    
    # Check for duplicate package file registries
    package_file_ids = Geo::PackageFileRegistry.group(:package_file_id).having('COUNT(*) > 1').pluck(:package_file_id)
    puts "Duplicate package file IDs count: #{package_file_ids.size}"
    puts 'Duplicate Package File IDs:', package_file_ids
    
    # Check for duplicate LFS object registries
    lfs_object_ids = Geo::LfsObjectRegistry.group(:lfs_object_id).having('COUNT(*) > 1').pluck(:lfs_object_id)
    puts "Duplicate LFS object IDs count: #{lfs_object_ids.size}"
    puts 'Duplicate LFS Object IDs:', lfs_object_ids
    
    # Check for duplicate pages deployment registries
    pages_deployment_ids = Geo::PagesDeploymentRegistry.group(:pages_deployment_id).having('COUNT(*) > 1').pluck(:pages_deployment_id)
    puts "Duplicate pages deployment IDs count: #{pages_deployment_ids.size}"
    puts 'Duplicate Pages Deployment IDs:', pages_deployment_ids
    
    # Check for duplicate terraform state version registries
    terraform_state_ids = Geo::TerraformStateVersionRegistry.group(:terraform_state_version_id).having('COUNT(*) > 1').pluck(:terraform_state_version_id)
    puts "Duplicate terraform state version IDs count: #{terraform_state_ids.size}"
    puts 'Duplicate Terraform State Version IDs:', terraform_state_ids
    

해결:

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 영향받은 각 유형에 대한 중복 레지스트리 항목을 제거합니다:

    # Remove duplicate upload registries
    upload_ids = Geo::UploadRegistry.group(:file_id).having('COUNT(*) > 1').pluck(:file_id)
    if upload_ids.any?
      Geo::UploadRegistry.where(file_id: upload_ids).delete_all
      puts "Removed #{upload_ids.size} duplicate upload registry entries"
    end
    
    # Remove duplicate job artifact registries
    artifact_ids = Geo::JobArtifactRegistry.group(:artifact_id).having('COUNT(*) > 1').pluck(:artifact_id)
    if artifact_ids.any?
      Geo::JobArtifactRegistry.where(artifact_id: artifact_ids).delete_all
      puts "Removed #{artifact_ids.size} duplicate job artifact registry entries"
    end
    
    # Remove duplicate package file registries
    package_file_ids = Geo::PackageFileRegistry.group(:package_file_id).having('COUNT(*) > 1').pluck(:package_file_id)
    if package_file_ids.any?
      Geo::PackageFileRegistry.where(package_file_id: package_file_ids).delete_all
      puts "Removed #{package_file_ids.size} duplicate package file registry entries"
    end
    
    # Remove duplicate LFS object registries
    lfs_object_ids = Geo::LfsObjectRegistry.group(:lfs_object_id).having('COUNT(*) > 1').pluck(:lfs_object_id)
    if lfs_object_ids.any?
      Geo::LfsObjectRegistry.where(lfs_object_id: lfs_object_ids).delete_all
      puts "Removed #{lfs_object_ids.size} duplicate LFS object registry entries"
    end
    
    # Remove duplicate pages deployment registries
    pages_deployment_ids = Geo::PagesDeploymentRegistry.group(:pages_deployment_id).having('COUNT(*) > 1').pluck(:pages_deployment_id)
    if pages_deployment_ids.any?
      Geo::PagesDeploymentRegistry.where(pages_deployment_id: pages_deployment_ids).delete_all
      puts "Removed #{pages_deployment_ids.size} duplicate pages deployment registry entries"
    end
    
    # Remove duplicate terraform state version registries
    terraform_state_ids = Geo::TerraformStateVersionRegistry.group(:terraform_state_version_id).having('COUNT(*) > 1').pluck(:terraform_state_version_id)
    if terraform_state_ids.any?
      Geo::TerraformStateVersionRegistry.where(terraform_state_version_id: terraform_state_ids).delete_all
      puts "Removed #{terraform_state_ids.size} duplicate terraform state version registry entries"
    end
    
  3. 모든 레지스트리 유형에서 정리를 확인합니다:

    # Verify no remaining duplicates
    upload_duplicates = Geo::UploadRegistry.group(:file_id).having('COUNT(*) > 1').count
    artifact_duplicates = Geo::JobArtifactRegistry.group(:artifact_id).having('COUNT(*) > 1').count
    package_duplicates = Geo::PackageFileRegistry.group(:package_file_id).having('COUNT(*) > 1').count
    lfs_duplicates = Geo::LfsObjectRegistry.group(:lfs_object_id).having('COUNT(*) > 1').count
    pages_duplicates = Geo::PagesDeploymentRegistry.group(:pages_deployment_id).having('COUNT(*) > 1').count
    terraform_duplicates = Geo::TerraformStateVersionRegistry.group(:terraform_state_version_id).having('COUNT(*) > 1').count
    
    puts "Remaining duplicates:"
    puts "  Uploads: #{upload_duplicates.size}"
    puts "  Job Artifacts: #{artifact_duplicates.size}"
    puts "  Package Files: #{package_duplicates.size}"
    puts "  LFS Objects: #{lfs_duplicates.size}"
    puts "  Pages Deployments: #{pages_duplicates.size}"
    puts "  Terraform State Versions: #{terraform_duplicates.size}"
    

오류: Checksum does not match the primary checksum#

가능한 근본 원인: 저장소 또는 컨테이너 레지스트리 검증 간격 변경으로 인한 체크섬 불일치.

진단:

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 실패한 저장소 또는 컨테이너 레지스트리를 확인합니다:

    failed_repos = Geo::ProjectRepositoryRegistry.failed.limit(100)
    failed_repos.each do |repo|
      puts "Project ID: #{repo.project_id}"
      puts "Primary checksum: #{repo.verification_checksum_mismatched}"
      puts "Secondary checksum: #{repo.verification_checksum}"
      puts "Error: #{repo.last_sync_failure}"
      puts "---"
    end
    
    failed_container_repos = Geo::ContainerRepositoryRegistry.failed.limit(100)
    failed_container_repos.each do |repo|
      puts "Container Repo Id: #{repo.model_record_id}"
      puts "Primary checksum: #{repo.verification_checksum_mismatched}"
      puts "Secondary checksum: #{repo.verification_checksum}"
      puts "Error: #{repo.last_sync_failure}"
      puts "---"
    end
    

해결:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 특정 프로젝트 또는 컨테이너 레지스트리에 대한 재검증을 강제합니다:

    project_ids = [1, 2, 3] # Replace with actual failing project IDs
    
    project_ids.each do |project_id|
      project = Project.find(project_id)
      puts "Reverifying project: #{project.full_path}"
    
      project_state = project.project_state
      project_state.update!(verification_state: 0)
    
      puts "Project #{project_id} marked for reverification"
    end
    
    container_repo_ids = [1, 2, 3]
    
    container_repo_ids.each do |repo_id|
      container_repo = ContainerRepository.find(repo_id)
      puts "Reverifying container repository: #{container_repo.path}"
    
      state = container_repo.container_repository_state
      state.update!(verification_state: 0)
    
      puts "Container Repo #{repo_id} marked for reverification"
    end
    

Error during verification: File is not checksummable에 대한 오브젝트 유형별 트러블슈팅#

Geo 데이터 유형마다 고유한 특성과 일반적인 실패 패턴이 있습니다. 이 섹션에서는 특정 오브젝트 유형에 대한 대상화된 트러블슈팅을 제공합니다.

업로드#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 업로드를 식별합니다:

    checksummable_failures = Upload.verification_failed
                                    .where("verification_failure LIKE '%File is not checksummable%'")
    
    puts "Found #{checksummable_failures.count} uploads with missing files"
    
    # Adjust 'limit' to count
    checksummable_failures.limit(5).each_with_index do |record, index|
      puts "Record #{index + 1}:"
      puts "  ID: #{record.id}"
      puts "  Path: #{record.path}"
      puts "  Model: #{record.model_type} (ID: #{record.model_id})"
      puts "  Created: #{record.created_at}"
      puts "---"
    end
    

해결:

Warning

업로드 레코드를 삭제하기 전에 최근의 작동하는 백업이 있는지 확인하세요. 팀과 협력하여 이러한 업로드를 제거해도 안전한지 확인하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 확인 후 문제가 있는 업로드를 제거합니다:

    # Remove individual upload
    Upload.find(55).destroy
    
    # Or remove all uploads with missing files (use with extreme caution)
    Upload.verification_failed.where("verification_failure LIKE '%File is not checksummable%'").destroy_all
    

페이지 배포#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 문제가 있는 페이지 배포를 검사합니다:

    checksummable_failures = PagesDeployment.verification_failed
                                            .where("verification_failure LIKE '%File is not checksummable%'")
    
    checksummable_failures.each_with_index do |record, index|
      puts "Record #{index + 1}:"
      puts "  ID: #{record.id}"
      puts "  Project: #{record.project.full_path}"
      puts "  Created: #{record.created_at}"
      puts "  File exists: #{record.file.exists?}"
      puts "---"
    end
    

해결:

Warning

페이지 배포 레코드를 삭제하기 전에 최근의 작동하는 백업이 있는지 확인하세요. 팀과 협력하여 이러한 배포를 제거해도 안전한지 확인하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 팀과 협력하여 배포를 제거해도 안전하다고 확인한 후:

    failed_ids = [21875, 21907, 21992] # Replace with actual IDs
    PagesDeployment.where(id: failed_ids).destroy_all
    puts "Removed #{failed_ids.size} problematic pages deployments"
    

LFS 오브젝트#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 문제가 있는 LFS 오브젝트를 검사합니다:

    checksummable_failures = LfsObject.verification_failed
                                      .where("verification_failure LIKE '%File is not checksummable%'")
    
    checksummable_failures.each_with_index do |record, index|
      puts "Record #{index + 1}:"
      puts "  OID: #{record.oid}"
      puts "  Size: #{record.size} bytes"
      puts "  File Store: #{record.file_store}"
      puts "  Created: #{record.created_at}"
    
      # Show associated projects
      associations = record.lfs_objects_projects.includes(:project)
      puts "  Associated projects (#{associations.count}):"
      associations.each do |assoc|
        project = assoc.project
        if project
          puts "    - #{project.full_path}"
        else
          puts "    - Project ID: #{assoc.project_id} (not found)"
        end
      end
      puts "---"
    end
    

해결:

Warning

LFS 오브젝트를 제거하면 해당 오브젝트를 참조하는 모든 프로젝트에 영향을 미칩니다. 삭제하기 전에 백업을 확보하고 프로젝트 관리자와 협력하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 LFS 오브젝트를 제거합니다:

    def destroy_lfs_not_checksummable(dry_run: true)
      lfs_objects = LfsObject.verification_failed.where("verification_failure like '%File is not checksummable%'")
      puts "Found #{lfs_objects.count} LFS objects that failed verification with 'File is not checksummable'."
    
      if dry_run
        puts "DRY RUN - No changes made"
        lfs_objects.each { |obj| puts "Would remove: OID #{obj.oid}, Size: #{obj.size}" }
        return
      end
    
      puts "Enter 'y' to continue with deletion: "
      prompt = STDIN.gets.chomp
      if prompt != 'y'
        puts "Exiting without action..."
        return
      end
    
      puts "Destroying all..."
      lfs_objects.each do |lfs_object|
        lfs_object.lfs_objects_projects.destroy_all
        lfs_object.destroy!
      end
      puts "Done!"
    end
    
    # Run in dry run mode first
    destroy_lfs_not_checksummable(dry_run: true)
    

작업 아티팩트#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 아티팩트를 확인합니다:

    failed_artifacts = Ci::JobArtifact.verification_failed.where("verification_failure LIKE '%File is not checksummable%'")
    
    failed_artifacts.each do |registry|
      artifact = Ci::JobArtifact.find_by(id: registry.id)
      if artifact
        puts "Artifact ID: #{artifact.id}"
        puts "Job ID: #{artifact.job_id}"
        puts "Project ID: #{artifact.project_id}"
        puts "File exists: #{artifact.file.exists?}"
        puts "File path: #{artifact.file.path}"
      else
        puts "Artifact ID #{artifact.id} not found in database"
      end
      puts "---"
    end
    

해결:

Warning

작업 아티팩트 레코드를 삭제하기 전에 최근의 작동하는 백업이 있는지 확인하세요. 팀과 협력하여 이러한 아티팩트를 제거해도 안전한지 확인하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 아티팩트를 정리합니다:

    def cleanup_missing_artifacts(dry_run: true)
      missing_file_artifacts = []
    
      Ci::JobArtifact.find_each do |artifact|
        unless artifact.file.exists?
          missing_file_artifacts << artifact.id
          puts "Missing file for artifact #{artifact.id}" if dry_run
        end
      end
    
      puts "Found #{missing_file_artifacts.size} artifacts with missing files"
    
      unless dry_run
        Ci::JobArtifact.where(id: missing_file_artifacts).destroy_all
        puts "Removed #{missing_file_artifacts.size} artifacts with missing files"
      end
    end
    
    # Run in dry run mode first
    cleanup_missing_artifacts(dry_run: true)
    

파이프라인 아티팩트#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 아티팩트를 확인합니다:

    failed_pipeline_artifacts = Ci::PipelineArtifact.verification_failed.where("verification_failure LIKE '%checksummable%'")
    
    failed_pipeline_artifacts.each do |registry|
      artifact = Ci::PipelineArtifact.find_by(id: registry.id)
      if artifact
        puts "Artifact ID: #{artifact.id}"
        puts "Pipeline ID: #{artifact.pipeline_id}"
        puts "Project ID: #{artifact.project_id}"
        puts "File exists: #{artifact.file.exists?}"
        puts "File path: #{artifact.file.path}"
      else
        puts "Artifact ID #{artifact.id} not found in database"
      end
      puts "---"
    end
    

해결:

Warning

파이프라인 아티팩트 레코드를 삭제하기 전에 최근의 작동하는 백업이 있는지 확인하세요. 팀과 협력하여 이러한 아티팩트를 제거해도 안전한지 확인하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 파이프라인 아티팩트를 제거합니다:

    def destroy_pipeline_artifacts_not_checksummable
      artifacts = Ci::PipelineArtifact.verification_failed.where("verification_failure like '%File is not checksummable%'")
      puts "Found #{artifacts.count} pipeline artifacts that failed verification with 'File is not checksummable'."
      puts "Enter 'y' to continue: "
      prompt = STDIN.gets.chomp
      if prompt != 'y'
        puts "Exiting without action..."
        return
      end
    
      puts "Destroying all..."
      artifacts.destroy_all
      puts "Done!"
    end
    
    destroy_pipeline_artifacts_not_checksummable
    

오류: Projects - Error during verification: Repository does not exist#

근본 원인: Git 저장소가 없는 프로젝트로 인한 검증 실패.

증상:

  • 검증 중에 프로젝트에 "Repository does not exist" 오류가 표시됩니다.
  • 합법적으로 저장소가 없는 프로젝트에 대한 Geo UI에서 잘못된 오류 보고.
  • 존재하지 않는 저장소에 대한 낭비적인 동기화 시도.

해결 방법:

존재하지 않는 경우 기본 사이트에서 프로젝트 저장소를 생성합니다:

puts "Found #{Project.verification_failed.count} project repos failed to checksum"
Project.verification_failed.find_each do |p|
  puts "#{p.full_path} #{p.ensure_repository.inspect}"
end

오류: Expected(200) <=> Actual(403 Forbidden)#

근본 원인: ListBucket 권한 누락으로 인해 S3 API가 404 대신 403을 반환합니다.

증상:

  • S3 엔드포인트가 있는 로그에 403 오류가 발생합니다.
  • S3 버킷에 대한 HEAD 요청이 실패합니다.
  • 오브젝트 스토리지 지원 데이터 유형에 대한 동기화 실패.

해결:

이를 위해서는 GitLab에서 사용하는 S3 IAM 정책에 ListBucket 권한을 추가하기 위한 인프라 팀 개입이 필요합니다.

메시지: Synchronization failed - Error syncing repository#

Warning

이 문제의 영향을 받는 대형 저장소의 경우 재동기화에 오랜 시간이 걸릴 수 있으며 Geo 사이트, 스토리지 및 네트워크 시스템에 상당한 부하를 줄 수 있습니다.

다음 오류 메시지는 저장소 동기화 시 일관성 검사 오류를 나타냅니다:

Synchronization failed - Error syncing repository [..] fatal: fsck error in packed object

이 오류를 트리거하는 여러 문제가 있습니다. 예를 들어, 이메일 주소 문제:

Error syncing repository: 13:fetch remote: "error: object : badEmail: invalid author/committer line - bad email
   fatal: fsck error in packed object
   fatal: fetch-pack: invalid index-pack output

이 오류를 트리거하는 또 다른 문제는 object : hasDotgit: contains '.git'입니다. 모든 저장소에 여러 문제가 있을 수 있으므로 특정 오류를 확인하세요.

두 번째 동기화 오류는 저장소 확인 문제로 인해 발생할 수도 있습니다:

Error syncing repository: 13:Received RST_STREAM with error code 2.

이러한 오류는 실패한 모든 저장소를 즉시 동기화하여 관찰할 수 있습니다.

일관성 오류를 일으키는 잘못된 형식의 오브젝트를 제거하려면 저장소 히스토리를 다시 작성해야 하며, 이는 일반적으로 선택 사항이 아닙니다.

이러한 일관성 검사를 무시하려면 보조 Geo 사이트의 Gitaly를 재구성하여 이러한 git fsck 문제를 무시하도록 합니다. 다음 구성 예제:

Gitaly 문서에 더 많은 세부 정보가 있으며, 다른 Git 검사 실패 및 이전 GitLab 버전에 대한 정보가 포함됩니다.

gitaly['configuration'] = {
  git: {
    config: [
      { key: "fsck.duplicateEntries", value: "ignore" },
      { key: "fsck.badFilemode", value: "ignore" },
      { key: "fsck.missingEmail", value: "ignore" },
      { key: "fsck.badEmail", value: "ignore" },
      { key: "fsck.hasDotgit", value: "ignore" },
      { key: "fetch.fsck.duplicateEntries", value: "ignore" },
      { key: "fetch.fsck.badFilemode", value: "ignore" },
      { key: "fetch.fsck.missingEmail", value: "ignore" },
      { key: "fetch.fsck.badEmail", value: "ignore" },
      { key: "fetch.fsck.hasDotgit", value: "ignore" },
      { key: "receive.fsck.duplicateEntries", value: "ignore" },
      { key: "receive.fsck.badFilemode", value: "ignore" },
      { key: "receive.fsck.missingEmail", value: "ignore" },
      { key: "receive.fsck.badEmail", value: "ignore" },
      { key: "receive.fsck.hasDotgit", value: "ignore" },
    ],
  },
}

fsck 오류의 포괄적인 목록은 Git 문서에서 찾을 수 있습니다.

GitLab 16.1 이상에서는 이러한 문제 중 일부를 해결할 수 있는 향상된 기능이 포함됩니다.

Gitaly 이슈 5625에서는 소스 저장소에 문제가 있는 커밋이 포함된 경우에도 Geo가 저장소를 복제하도록 제안합니다.

관련 오류 does not appear to be a git repository#

Synchronization failed - Error syncing repository 오류 메시지와 함께 다음 로그 메시지가 표시될 수 있습니다. 이 오류는 보조 Geo 사이트의 파일 시스템에 있는 저장소의 .git/config 파일에 예상되는 Geo 원격이 없음을 나타냅니다:

{
  "created": "@1603481145.084348757",
  "description": "Error received from peer unix:/var/opt/gitlab/gitaly/gitaly.socket","grpc_message": "exit status 128",
  "grpc_status": 13
}
{"grpc.request.fullMethod": "/gitaly.RemoteService/FindRemoteRootRef",
  "grpc.request.glProjectPath": "<namespace>/<project>","level": "error",
  "msg": "fatal: 'geo' does not appear to be a git repository
          fatal: Could not read from remote repository. …",
}

이를 해결하려면:

  1. 보조 Geo 사이트의 웹 인터페이스에 로그인합니다.

  2. .git 폴더를 백업합니다.

  3. 선택적으로, 일부 ID를 샘플 확인하여 실제로 알려진 Geo 복제 실패가 있는 프로젝트에 해당하는지 확인합니다. fatal: 'geo'grep 검색어로 사용하고 다음 API 호출을 사용합니다:

    curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<first_failed_geo_sync_ID>"
    
  4. Rails 콘솔을 열고 다음을 실행합니다:

    failed_project_registries = Geo::ProjectRepositoryRegistry.failed
    
    if failed_project_registries.any?
      puts "Found #{failed_project_registries.count} failed project repository registry entries:"
    
      failed_project_registries.each do |registry|
        puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Last Sync Failure: '#{registry.last_sync_failure}'"
      end
    else
      puts "No failed project repository registry entries found."
    end
    
  5. 각 프로젝트에 대한 새 동기화를 실행하기 위해 다음 명령을 실행합니다:

    failed_project_registries.each do |registry|
      registry.replicator.sync
      puts "Sync initiated for registry ID: #{registry.id}, Project ID: #{registry.project_id}"
    end
    

백필 중 실패#

백필 중 실패는 백필 큐 끝에서 재시도가 예약되므로, 이러한 실패는 백필이 완료된 후에 해결됩니다.

메시지: unexpected disconnect while reading sideband packet#

불안정한 네트워킹 조건으로 인해 기본 사이트에서 대용량 저장소 데이터를 가져오려고 할 때 Gitaly가 실패할 수 있습니다. 이러한 조건으로 인해 이 오류가 발생할 수 있습니다:

curl 18 transfer closed with outstanding read data remaining & fetch-pack:
unexpected disconnect while reading sideband packet

이 오류는 사이트 간에 저장소를 처음부터 복제해야 하는 경우 더 발생하기 쉽습니다.

Geo는 여러 번 재시도하지만 네트워크 중단으로 인해 전송이 지속적으로 중단되는 경우 rsync와 같은 대체 방법을 사용하여 git을 우회하고 Geo에서 복제에 실패하는 저장소의 초기 복사본을 만들 수 있습니다.

각 실패한 저장소를 개별적으로 전송하고 각 전송 후 일관성을 확인하는 것이 좋습니다. rsync를 다른 서버로 지침에 따라 각 영향받은 저장소를 기본 사이트에서 보조 사이트로 전송합니다.

Geo 보조 사이트에서 저장소 확인 실패 찾기#

Note

모든 저장소 데이터 유형이 GitLab 16.3의 Geo Self-Service Framework로 마이그레이션됐습니다. 이 기능을 Geo Self-Service Framework에 다시 구현하기 위한 이슈가 있습니다.

GitLab 16.2 이하의 경우:

모든 프로젝트에 대해 활성화된 경우 저장소 확인은 Geo 보조 사이트에서도 수행됩니다. 메타데이터는 Geo 추적 데이터베이스에 저장됩니다.

Geo 보조 사이트에서의 저장소 확인 실패가 반드시 복제 문제를 의미하지는 않습니다. 다음은 이러한 실패를 해결하기 위한 일반적인 접근 방식입니다.

  1. 아래에 언급된 대로 영향받은 저장소와 기록된 오류를 찾습니다.
  2. 특정 git fsck 오류를 진단하려고 합니다. 가능한 오류 범위가 넓으므로 검색 엔진에서 검색해 보세요.
  3. 영향받은 저장소의 일반적인 기능을 테스트합니다. 보조 사이트에서 Pull하고 파일을 봅니다.
  4. 기본 사이트의 저장소 복사본에 동일한 git fsck 오류가 있는지 확인합니다. 페일오버를 계획 중이라면 보조 사이트가 기본 사이트와 동일한 정보를 갖도록 우선 순위를 정하는 것을 고려하세요. 기본 사이트의 백업을 확보하고 계획된 페일오버 지침을 따르세요.
  5. 기본 사이트에 Push하고 변경 사항이 보조 사이트에 복제되는지 확인합니다.
  6. 복제가 자동으로 작동하지 않으면 저장소를 수동으로 동기화하려고 합니다.

다음 기본 트러블슈팅 단계를 수행하려면 Rails 콘솔 세션을 시작합니다.

Warning

데이터를 변경하는 명령은 올바르게 실행되지 않거나 올바른 조건에서 실행되지 않으면 손상을 일으킬 수 있습니다. 항상 먼저 테스트 환경에서 명령을 실행하고 복원 준비가 된 백업 인스턴스를 마련하세요.

저장소 확인에 실패한 저장소 수 가져오기#

Geo::ProjectRegistry.where(last_repository_check_failed: true).count

저장소 확인에 실패한 저장소 찾기#

Geo::ProjectRegistry.where(last_repository_check_failed: true)

Gitaly 클러스터에서 저장소를 강제 삭제하고 재동기화#

Warning

이 절차는 위험하고 과도합니다. 다른 트러블슈팅 방법이 실패한 경우에만 최후 수단으로 사용하세요. 이 절차는 저장소가 재동기화될 때까지 일시적인 데이터 손실을 야기합니다.

이 절차는 보조 사이트의 Gitaly 클러스터에서 저장소를 삭제하고 다시 동기화합니다. 위험을 이해하고 이러한 모든 조건이 사실인 경우에만 사용을 고려해야 합니다:

  • 기본 사이트의 저장소에 대해 git clone이 작동합니다.
  • p.replicator.sync_repository(여기서 p는 프로젝트 모델 인스턴스)가 보조 사이트에서 Gitaly 오류를 기록합니다.
  • 표준 트러블슈팅으로 문제가 해결되지 않았습니다.

전제 조건:

  • 보조 사이트의 Rails 콘솔과 Praefect 노드 모두에 대한 관리자 액세스 권한이 있는지 확인합니다.
  • 기본 사이트에서 저장소가 액세스 가능하고 올바르게 작동하는지 확인합니다.
  • 이 절차를 되돌려야 하는 경우를 위한 백업 계획을 갖추세요.

수행 방법:

  1. 보조 사이트의 Rails 콘솔에 로그인합니다.

  2. 다음 옵션 중 하나를 사용하여 프로젝트 모델을 인스턴스화하고 p 변수에 저장합니다:

    • 영향받은 프로젝트 ID(예: 60087)를 알고 있는 경우:

      p = Project.find(60087)
      
    • GitLab에서 영향받은 프로젝트 경로(예: my-group/my-project)를 알고 있는 경우:

      p = Project.find_by_full_path('my-group/my-project')
      
  3. 프로젝트 Git 저장소의 가상 스토리지를 출력하고 나중을 위해 기록합니다:

    p.repository.storage
    

    예제 출력:

    irb(main):002:0> p.repository.storage
    => "default"
    
  4. 프로젝트 Git 저장소의 상대 경로를 출력하고 나중을 위해 기록합니다:

    p.repository.disk_path + '.git'
    

    예제 출력:

    irb(main):003:0> p.repository.disk_path + '.git'
    => "@hashed/66/b2/66b2fc8562b3432399acc2d0108fcd2782b32bd31d59226c7a03a20b32c76ee8.git"
    
  5. 보조 사이트의 Praefect 노드에 SSH로 접속합니다.

  6. 이전 단계에서 기록한 가상 스토리지와 상대 경로를 사용하여 Gitaly 클러스터에서 저장소를 수동으로 제거하는 절차를 따릅니다.

    보조 사이트의 Git 저장소가 삭제됩니다.

  7. Rails 콘솔에서 재동기화하기 전에 상관 ID를 설정합니다. 이 ID는 이 세션에서 실행하는 명령과 관련된 모든 로그를 검색하는 데 도움이 됩니다:

    Gitlab::ApplicationContext.push({})
    

    예제 출력:

    [2] pry(main)> Gitlab::ApplicationContext.push({})
    => #"53da64ae800bd4794a2b61ab1c80b028"}>
    
  8. 프로젝트 Git 저장소를 동기화합니다:

    p.replicator.sync_repository
    

Git 저장소는 이제 기본 사이트에서 보조 사이트로 재동기화되어야 합니다. Geo 관리자 인터페이스를 통해 또는 Rails 콘솔에서 저장소의 동기화 상태를 확인하여 동기화 프로세스를 모니터링합니다.

인프라 및 성능 고려사항#

일부 동기화 문제는 인프라 수준 문제 또는 성능 제약으로 인해 발생합니다.

높은 동시성 문제#

과도한 Geo 검증 동시성이 데이터베이스를 압도하고 동기화 실패를 일으킬 수 있습니다.

증상:

  • 데이터베이스 연결 시간 초과
  • 데이터베이스 서버의 높은 CPU 사용량
  • 정상적인 인프라에도 불구하고 느린 동기화 진행

진단 및 해결:

기본 사이트에서 UI를 통해 동시성 설정을 줄입니다.

수동 동기화 상태 업데이트#

경우에 따라 기본 문제를 해결한 후 오브젝트 유형을 수동으로 동기화됨으로 표시해야 할 수 있습니다. 이 시나리오는 보조 사이트의 오브젝트 버킷에 파일을 수동으로 업로드하는 방법으로만 문제를 수정할 수 있을 때 발생합니다. 일반적으로 이 작업이 필요하지 않지만 버전 버그로 인해 발생할 수 있습니다. 다음은 수동으로 업로드된 오브젝트 유형(이 경우 업로드)을 동기화됨으로 표시하는 방법을 보여줍니다.

Warning

파일이 보조 사이트에 실제로 존재하고 액세스 가능한지 확인한 경우에만 오브젝트를 동기화됨으로 표시하세요.

def mark_upload_synced(upload_id)
  upload = Upload.find(upload_id)
  registry = upload.replicator.registry
  registry.start
  registry.synced!
  puts "Marked upload #{upload_id} as synced"
end

# Mark specific uploads as synced
upload_ids = [107221, 107320] # Replace with actual IDs
upload_ids.each { |id| mark_upload_synced(id) }

Geo 보조 사이트 복제 재설정#

보조 사이트가 손상된 상태에 있고 복제 상태를 처음부터 다시 시작하도록 재설정하려는 경우 도움이 될 수 있는 몇 가지 단계가 있습니다:

  1. Sidekiq와 Geo Log Cursor를 중지합니다.

    Sidekiq가 정상적으로 중지되도록 만들 수 있지만 새 작업 받기를 중지하고 현재 작업이 처리를 마칠 때까지 기다리게 합니다.

    첫 번째 단계에는 SIGTSTP 킬 신호를 보내고 모든 작업이 완료되면 SIGTERM을 보내야 합니다. 그렇지 않으면 gitlab-ctl stop 명령을 사용합니다.

    gitlab-ctl status sidekiq
    # run: sidekiq: (pid 10180) <- this is the PID you will use
    kill -TSTP 10180 # change to the correct PID
    
    gitlab-ctl stop sidekiq
    gitlab-ctl stop geo-logcursor
    

    Sidekiq 로그를 확인하여 Sidekiq 작업 처리가 완료됐는지 알 수 있습니다:

    gitlab-ctl tail sidekiq
    
  2. Gitaly 및 Gitaly 클러스터(Praefect) 데이터를 지웁니다.

   mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
   sudo gitlab-ctl reconfigure
  1. 선택적으로 Praefect 내부 로드 밸런서를 비활성화합니다.
    1. 각 Praefect 서버에서 Praefect를 중지합니다:

      sudo gitlab-ctl stop praefect
      
    2. Praefect 데이터베이스를 재설정합니다:

      sudo /opt/gitlab/embedded/bin/psql -U praefect -d template1 -h localhost -c "DROP DATABASE praefect_production WITH (FORCE);"
      sudo /opt/gitlab/embedded/bin/psql -U praefect -d template1 -h localhost -c "CREATE DATABASE praefect_production WITH OWNER=praefect ENCODING=UTF8;"
      
    3. 각 Gitaly 노드에서 저장소 데이터를 이름 변경/삭제합니다:

      sudo mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
      sudo gitlab-ctl reconfigure
      
    4. Praefect 배포 노드에서 재구성을 실행하여 데이터베이스를 설정합니다:

      sudo gitlab-ctl reconfigure
      
    5. 각 Praefect 서버에서 Praefect를 시작합니다:

      sudo gitlab-ctl start praefect
      
    6. 선택적으로 비활성화한 경우 Praefect 내부 로드 밸런서를 다시 활성화합니다.

[!note] 더 이상 필요하지 않다고 확인되면 나중에 디스크 공간을 절약하기 위해 /var/opt/gitlab/git-data/repositories.old를 제거할 수 있습니다.

  1. 선택적으로 다른 데이터 폴더의 이름을 변경하고 새 폴더를 만듭니다.

    [!warning] 기본 사이트에서 제거됐지만 이 제거가 반영되지 않은 파일이 보조 사이트에 여전히 있을 수 있습니다. 이 단계를 건너뛰면 이러한 파일이 Geo 보조 사이트에서 제거되지 않습니다.

    업로드된 콘텐츠(파일 첨부, 아바타 또는 LFS 오브젝트 등)는 다음 경로 중 하나의 하위 폴더에 저장됩니다:

    • /var/opt/gitlab/gitlab-rails/shared
    • /var/opt/gitlab/gitlab-rails/uploads

    모두 이름을 변경하려면:

    gitlab-ctl stop
    
    mv /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared.old
    mkdir -p /var/opt/gitlab/gitlab-rails/shared
    
    mv /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads.old
    mkdir -p /var/opt/gitlab/gitlab-rails/uploads
    
    gitlab-ctl start postgresql
    gitlab-ctl start geo-postgresql
    

    폴더를 다시 만들고 권한 및 소유권이 올바른지 확인하려면 재구성합니다:

    gitlab-ctl reconfigure
    
  2. 추적 데이터베이스를 재설정합니다.

    [!warning] 선택적 단계 3을 건너뛴 경우 geo-postgresqlpostgresql 서비스가 모두 실행 중인지 확인하세요.

    gitlab-rake db:drop:geo DISABLE_DATABASE_ENVIRONMENT_CHECK=1   # on a secondary app node
    gitlab-ctl reconfigure     # on the tracking database node
    gitlab-rake db:migrate:geo # on a secondary app node
    
  3. 이전에 중지한 서비스를 다시 시작합니다.

    gitlab-ctl start
    

Geo 동기화 및 검증 오류 트러블슈팅

Tier: Premium, Ultimate
Offering: GitLab Self-Managed
원문 보기
요약

Admin > Geo > Sites 또는 동기화 상태 Rake 작업에서 복제 또는 검증 실패가 발생하면 다음 일반 단계를 통해 해결을 시도할 수 있습니다: 수동 재시도를 시도하기 전에 향상된 진단 절차를 사용하여 동기화 문제의 범위와 성격을 더 잘 이해할 수 있습니다.

Admin > Geo > Sites 또는 동기화 상태 Rake 작업에서 복제 또는 검증 실패가 발생하면 다음 일반 단계를 통해 해결을 시도할 수 있습니다:

  1. Geo는 자동으로 실패를 재시도합니다. 실패가 새로 발생했거나 수가 적거나, 근본 원인이 이미 해결됐다고 판단되면 실패가 사라질 때까지 기다릴 수 있습니다.
  2. 실패가 오랫동안 지속됐다면 이미 여러 번 재시도가 발생한 것이며, 자동 재시도 간격이 실패 유형에 따라 최대 4시간으로 늘어납니다. 근본 원인이 이미 해결됐다고 판단되면 수동으로 복제 또는 검증을 재시도하여 대기 시간을 줄일 수 있습니다.
  3. 실패가 지속되면 다음 섹션을 통해 해결을 시도하세요.

진단 절차#

수동 재시도를 시도하기 전에 향상된 진단 절차를 사용하여 동기화 문제의 범위와 성격을 더 잘 이해할 수 있습니다.

모델 상태 확인#

이 절차는 모든 Geo 데이터 유형 모델 클래스에 대한 자세한 상태 정보를 제공하며 체크섬 실패를 식별하는 데 도움이 됩니다. 이러한 실패는 복제 가능 객체의 체크섬을 계산할 수 없을 때 발생합니다. "기본 검증 실패"라고도 합니다.

체크섬 실패는 UI 또는 Rails 콘솔에서 확인할 수 있습니다.

기본 사이트에서 데이터 관리 페이지를 사용하세요.

다음 스크립트를 사용하여 각 모델 유형에 대한 자세한 정보를 출력할 수 있습니다:

  • 레코드 총 수
  • 실패, 검증됨, 대기 중인 레코드 수
  • 조사를 위한 실패 레코드 샘플
Note

ModelMapper 클래스는 GitLab 18.3에서 추가됐습니다. 이전 버전에서는 Geo 데이터 유형 모델 클래스 목록을 수동으로 지정해야 합니다.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 다음 스크립트를 실행하여 포괄적인 개요를 확인하세요:

    def output_geo_verification_failures
      model_classes = ::Gitlab::Geo::ModelMapper.available_models
    
      model_classes.each do |klass|
        total = klass.count
        state_klass = klass.verification_state_table_class
        failed_examples = []
    
        puts "\n=== #{klass.name} ==="
        puts "Total: #{total}"
        ::Geo::VerificationState::VERIFICATION_STATE_VALUES.each do |key, value|
          records = state_klass.where(verification_state: value)
          failed_examples = records if key == 'verification_failed'
    
          puts "#{key.gsub('verification_', '').camelize}: #{records.size}"
        end
    
        if failed_examples.any?
          puts "\nSample failed records:"
          failed_examples.limit(3).each { |record| puts "  ID: #{record.id}, Checksum: #{record.verification_checksum || 'nil'}, Error: #{record.verification_failure}" }
        end
      end
    
      nil
    end
    
    output_geo_verification_failures
    

레지스트리 상태 확인#

이 절차는 모든 Geo 레지스트리 유형에 대한 자세한 상태 정보를 제공하며 실패 패턴을 식별하는 데 도움이 됩니다.

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 다음 스크립트를 실행하여 포괄적인 개요를 확인하세요:

    def output_geo_failures()
      registry_classes = [
        Geo::UploadRegistry,
        Geo::JobArtifactRegistry,
        Geo::PackageFileRegistry,
        Geo::PagesDeploymentRegistry,
        Geo::ProjectRepositoryRegistry,
        Geo::TerraformStateVersionRegistry,
        Geo::MergeRequestDiffRegistry,
        Geo::LfsObjectRegistry,
        Geo::PipelineArtifactRegistry,
        Geo::CiSecureFileRegistry
      ]
    
      registry_classes.each do |klass|
        puts "\n=== #{klass.name} ==="
        puts "Total: #{klass.count}"
        puts "Failed: #{klass.failed.count}"
        puts "Synced: #{klass.synced.count}"
        puts "Pending: #{klass.pending.count}"
        puts "Started: #{klass.with_state(:started).count}"
    
        if klass.failed.count > 0
           puts "\nSample failed records:"
           klass.failed.limit(3).each { |record| puts "  ID: #{record.id}, Error: #{record.last_sync_failure}" }
        end
      end
    
      nil
    end
    
    output_geo_failures()
    
  3. 이 스크립트는 각 레지스트리 유형에 대한 자세한 정보를 출력합니다:

    • 레코드 총 수
    • 실패, 동기화됨, 대기 중인 레코드 수
    • 조사를 위한 실패 레코드 샘플

복제 또는 검증 수동 재시도#

보조 Geo 사이트의 Rails 콘솔에서 다음을 수행할 수 있습니다:

개별 컴포넌트 재동기화 및 재검증#

보조 사이트에서 Admin > Geo > Replication으로 이동하여 개별 항목을 강제로 재동기화하거나 재검증할 수 있습니다.

그러나 이 방법이 작동하지 않는 경우 Rails 콘솔을 사용하여 동일한 작업을 수행할 수 있습니다. 다음 섹션에서는 Rails 콘솔의 내부 애플리케이션 명령을 사용하여 개별 레코드에 대한 복제 또는 검증을 동기적 또는 비동기적으로 유발하는 방법을 설명합니다.

Replicator 인스턴스 획득#

Warning

데이터를 변경하는 명령은 올바르게 실행되지 않거나 올바른 조건에서 실행되지 않으면 손상을 일으킬 수 있습니다. 항상 먼저 테스트 환경에서 명령을 실행하고 복원 준비가 된 백업 인스턴스를 마련하세요.

동기화 또는 검증 작업을 수행하기 전에 Replicator 인스턴스를 획득해야 합니다.

먼저, 수행하려는 작업에 따라 기본 또는 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

기본 사이트에서:

  • 리소스를 체크섬할 수 있습니다.

보조 사이트에서:

  • 리소스를 동기화할 수 있습니다.
  • 리소스를 체크섬하고 해당 체크섬을 기본 사이트의 체크섬과 비교하여 검증할 수 있습니다.

다음으로, 다음 스니펫 중 하나를 실행하여 Replicator 인스턴스를 가져옵니다.

모델 레코드의 ID로 가져오기#
model_record = Packages::PackageFile.find_by(id: 123)
replicator = model_record.replicator
레지스트리 레코드의 ID로 가져오기#
  • 432를 실제 ID로 교체하세요. 레지스트리 레코드는 추적하는 모델 레코드와 동일한 ID 값을 가질 수도 있고 그렇지 않을 수도 있습니다.
  • Geo::PackageFileRegistryGeo 레지스트리 클래스 중 하나로 교체하세요.

보조 Geo 사이트에서:

registry_record = Geo::PackageFileRegistry.find_by(id: 432)
replicator = registry_record.replicator
레지스트리 레코드의 last_sync_failure에 있는 오류 메시지로 가져오기#
  • Geo::PackageFileRegistryGeo 레지스트리 클래스 중 하나로 교체하세요.
  • error message here를 실제 오류 메시지로 교체하세요.
registry = Geo::PackageFileRegistry.find_by("last_sync_failure LIKE '%error message here%'")
replicator = registry.replicator
레지스트리 레코드의 verification_failure에 있는 오류 메시지로 가져오기#
  • Geo::PackageFileRegistryGeo 레지스트리 클래스 중 하나로 교체하세요.
  • error message here를 실제 오류 메시지로 교체하세요.
registry = Geo::PackageFileRegistry.find_by("verification_failure LIKE '%error message here%'")
replicator = registry.replicator

Replicator 인스턴스로 작업 수행#

replicator 변수에 Replicator 인스턴스를 저장한 후 여러 작업을 수행할 수 있습니다:

콘솔에서 동기화#

이 스니펫은 보조 사이트에서만 작동합니다.

이는 콘솔에서 동기화 코드를 동기적으로 실행하므로 리소스 동기화에 얼마나 걸리는지 관찰하거나 전체 오류 백트레이스를 볼 수 있습니다.

replicator.sync

선택적으로, 콘솔의 로그 수준을 설정된 로그 수준보다 더 자세하게 만든 다음 동기화를 수행하세요:

Rails.logger.level = :debug
콘솔에서 체크섬 또는 검증#

이 스니펫은 모든 기본 또는 보조 사이트에서 작동합니다.

기본 사이트에서는 리소스를 체크섬하고 결과를 메인 GitLab 데이터베이스에 저장합니다. 보조 사이트에서는 리소스를 체크섬하고 메인 GitLab 데이터베이스의 체크섬(기본 사이트에서 생성된)과 비교하여 결과를 Geo 추적 데이터베이스에 저장합니다.

이는 콘솔에서 체크섬 및 검증 코드를 동기적으로 실행하므로 얼마나 걸리는지 관찰하거나 전체 오류 백트레이스를 볼 수 있습니다.

replicator.verify
Sidekiq 작업에서 동기화#

이 스니펫은 보조 사이트에서만 작동합니다.

리소스의 동기화를 수행하기 위해 Sidekiq 작업을 큐에 넣습니다.

replicator.enqueue_sync
Sidekiq 작업에서 검증#

이 스니펫은 모든 기본 또는 보조 사이트에서 작동합니다.

리소스의 체크섬 또는 검증을 수행하기 위해 Sidekiq 작업을 큐에 넣습니다.

replicator.verify_async
모델 레코드 가져오기#

이 스니펫은 모든 기본 또는 보조 사이트에서 작동합니다.

replicator.model_record
레지스트리 레코드 가져오기#

이 스니펫은 레지스트리 테이블이 Geo 추적 DB에 저장되므로 보조 사이트에서만 작동합니다.

replicator.registry

Geo 데이터 유형 모델 클래스#

Geo 데이터 유형은 하나 이상의 GitLab 기능에 필요한 데이터를 저장하고 Geo에 의해 보조 사이트로 복제되는 특정 데이터 클래스입니다.

  • Blob 유형:
    • Ci::JobArtifact
    • Ci::PipelineArtifact
    • Ci::SecureFile
    • LfsObject
    • MergeRequestDiff
    • Packages::PackageFile
    • PagesDeployment
    • Terraform::StateVersion
    • Upload
    • DependencyProxy::Manifest
    • DependencyProxy::Blob
  • Git 저장소 유형:
    • DesignManagement::Repository
    • ProjectRepository
    • ProjectWikiRepository
    • SnippetRepository
    • GroupWikiRepository
  • 기타 유형:
    • ContainerRepository

주요 클래스 종류는 Registry, Model, Replicator입니다. 이 클래스 중 하나의 인스턴스가 있으면 다른 것을 가져올 수 있습니다. Registry와 Model은 주로 PostgreSQL DB 상태를 관리합니다. Replicator는 PostgreSQL 외 데이터(파일/Git 저장소/컨테이너 저장소)를 복제하거나 검증하는 방법을 알고 있습니다.

Geo 레지스트리 클래스#

GitLab Geo의 맥락에서 레지스트리 레코드는 Geo 추적 데이터베이스의 레지스트리 테이블을 가리킵니다. 각 레코드는 LFS 파일이나 프로젝트 Git 저장소와 같이 메인 GitLab 데이터베이스의 단일 복제 가능 항목을 추적합니다. 쿼리할 수 있는 Geo 레지스트리 테이블에 해당하는 Rails 모델은:

  • Blob 유형:
    • Geo::CiSecureFileRegistry
    • Geo::DependencyProxyBlobRegistry
    • Geo::DependencyProxyManifestRegistry
    • Geo::JobArtifactRegistry
    • Geo::LfsObjectRegistry
    • Geo::MergeRequestDiffRegistry
    • Geo::PackageFileRegistry
    • Geo::PagesDeploymentRegistry
    • Geo::PipelineArtifactRegistry
    • Geo::ProjectWikiRepositoryRegistry
    • Geo::SnippetRepositoryRegistry
    • Geo::TerraformStateVersionRegistry
    • Geo::UploadRegistry
  • Git 저장소 유형:
    • Geo::DesignManagementRepositoryRegistry
    • Geo::ProjectRepositoryRegistry
    • Geo::ProjectWikiRepositoryRegistry
    • Geo::SnippetRepositoryRegistry
    • Geo::GroupWikiRepositoryRegistry
  • 기타 유형:
    • Geo::ContainerRepositoryRegistry

여러 컴포넌트 재동기화 및 재검증#

히스토리
  • 대량 재동기화 및 재검증 기능이 GitLab 16.5에서 추가됨.

컴포넌트 리소스 동기화 또는 검증에 실패하면 대량 작업을 트리거하여 복제 큐를 다시 시작할 수 있습니다. 이러한 작업은 재시도 횟수와 예약 시간을 0으로 재설정하여 시스템이 최대 1시간을 기다리지 않고 더 빨리 실패한 리소스를 처리하도록 합니다.

Note

이러한 작업은 리소스를 즉시 처리하지 않습니다. 대신 동기화 및 검증을 처리하는 백그라운드 작업을 다시 큐에 넣습니다. 실제 복제 작업은 표준 Geo 복제 프로세스를 통해 비동기적으로 발생합니다.

재동기화 및 재검증 작동 방식#

재동기화 또는 재검증 작업을 트리거하면 시스템은 일치하는 레코드를 pending으로 표시합니다. Geo 재동기화 및 재검증 백그라운드 워커가 이러한 레코드를 선택하고 일반 큐 우선 순위에 따라 처리합니다. 이 메커니즘을 사용하면 작업을 즉시 차단하지 않고 실패한 리소스 처리를 앞당길 수 있습니다.

Note

성공적으로 동기화되지 않은 레코드는 재검증할 수 없습니다. 동기화된 레코드만 검증할 수 있습니다.

UI 또는 Rails 콘솔에서 대량 작업을 트리거할 수 있습니다.

UI에서#

UI에서 한 컴포넌트의 모든 리소스에 대한 전체 재동기화를 예약할 수 있습니다:

  1. 오른쪽 상단에서 Admin을 선택합니다.
  2. 왼쪽 사이드바에서 Geo > Sites를 선택합니다.
  3. Replication details 아래에서 원하는 컴포넌트를 선택합니다.
선택한 컴포넌트에 대한 리소스 재동기화#
  1. Resync all 선택: 이미 동기화됐는지 여부에 관계없이 선택한 리소스의 모든 레코드 상태를 재설정합니다.
  2. Resync all failed 선택: 동기화에 실패한 모든 레코드를 재설정합니다.
선택한 컴포넌트에 대한 리소스 재검증#
  1. Reverify all 선택: 이미 검증됐는지 여부에 관계없이 선택한 리소스의 모든 레코드 상태를 재설정합니다.
  2. Reverify all failed 선택: 검증에 실패했지만 동기화에 성공한 모든 레코드를 재설정합니다.
모든 사이트에서 하나의 컴포넌트 재검증#

기본 사이트의 체크섬에 의문이 있는 경우 기본 사이트가 체크섬을 다시 계산하도록 해야 합니다. 이후 기본 사이트에서 각 체크섬이 재계산된 후 이벤트가 생성되어 모든 보조 사이트로 전파되고 체크섬을 재계산하여 값을 비교합니다. 불일치가 발생하면 레지스트리를 sync failed로 표시하여 동기화 재시도가 예약됩니다.

UI에서 기본 사이트의 체크섬을 재계산할 수 있습니다:

  1. 오른쪽 상단에서 Admin을 선택합니다.
  2. 왼쪽 사이드바에서 Monitoring > Data management를 선택합니다.
  3. 드롭다운 목록에서 원하는 컴포넌트를 선택합니다.
  4. Checksum all을 선택합니다.
Warning

Resync all, Reverify all, Checksum all은 이미 동기화되거나 검증된 여부에 관계없이 모든 리소스의 업데이트를 트리거합니다. 인스턴스에 특정 객체 유형이 수천 개 있는 경우(예: CI Job Artifacts) 실행하지 마세요.

Rails 콘솔에서#

Warning

데이터를 변경하는 명령은 올바르게 실행되지 않거나 올바른 조건에서 실행되지 않으면 손상을 일으킬 수 있습니다. 항상 먼저 테스트 환경에서 명령을 실행하고 복원 준비가 된 백업 인스턴스를 마련하세요.

다음 섹션에서는 Rails 콘솔의 내부 애플리케이션 명령을 사용하여 대량 복제 또는 검증을 유발하는 방법을 설명합니다.

동기화에 실패한 하나의 컴포넌트의 모든 리소스 동기화#

다음 스크립트:

  • 모든 실패한 저장소를 반복합니다.
  • 마지막 실패 이유를 포함한 Geo 동기화 및 검증 메타데이터를 표시합니다.
  • 저장소를 다시 동기화하려고 시도합니다.
  • 실패가 발생하면 이유와 함께 보고합니다.
  • 완료하는 데 시간이 걸릴 수 있습니다. 결과를 보고하기 전에 각 저장소 검사가 완료되어야 합니다. 세션이 시간 초과되면 screen 세션을 시작하거나 Rails runnernohup을 사용하여 프로세스가 계속 실행되도록 조치를 취하세요.

보조 Geo 사이트에서 이 스크립트를 실행하세요.

Geo::ProjectRepositoryRegistry.failed.find_each do |registry|
   begin
     puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Last Sync Failure: '#{registry.last_sync_failure}'"
     registry.replicator.sync
     puts "Sync initiated for registry ID: #{registry.id}"
   rescue => e
     puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Failed: '#{e}'", e.backtrace.join("\n")
   end
end; nil
기본 사이트에서 체크섬에 실패한 모든 리소스 재검증#

시스템은 기본 사이트에서 체크섬에 실패한 모든 리소스를 자동으로 재검증하지만, 과도한 양의 실패를 방지하기 위해 점진적 백오프 방식을 사용합니다.

선택적으로, 예를 들어 개입 시도를 완료한 경우 더 빨리 재검증을 수동으로 트리거할 수 있습니다:

  1. 기본 사이트의 GitLab Rails 노드에 SSH로 로그인합니다.

  2. Rails 콘솔을 엽니다.

  3. UploadGeo 데이터 유형 모델 클래스 중 하나로 교체하여 모든 리소스를 pending verification으로 표시합니다:

    Upload.verification_state_table_class.where(verification_state: 3).each_batch do |relation|
      relation.update_all(verification_state: 0)
    end
    

오류#

메시지: The file is missing on the Geo primary site#

동기화 실패 The file is missing on the Geo primary site는 처음 보조 Geo 사이트를 설정할 때 기본 사이트의 데이터 불일치로 인해 일반적으로 발생합니다.

데이터 불일치와 파일 누락은 GitLab을 운영하면서 시스템 또는 인적 오류로 인해 발생할 수 있습니다. 예를 들어, 인스턴스 관리자가 로컬 파일 시스템에서 여러 아티팩트를 수동으로 삭제합니다. 이러한 변경 사항은 데이터베이스에 제대로 전파되지 않아 불일치가 발생합니다. 이러한 불일치는 유지되어 마찰을 일으킬 수 있습니다. Geo 보조 사이트는 데이터베이스에 여전히 참조되지만 더 이상 존재하지 않는 파일들을 계속 복제하려고 시도할 수 있습니다.

Note

최근 로컬에서 오브젝트 스토리지로 마이그레이션한 경우 전용 오브젝트 스토리지 트러블슈팅 섹션을 참조하세요.

불일치 식별#

이 오류를 조사하려면 불일치 가능한 내용을 찾아야 합니다. 불일치는 Admin > Geo > Sites의 동기화 상태 또는 UI의 다른 곳에서 확인할 수 있습니다.

기본 사이트에서 데이터 관리 페이지를 사용하세요.

누락된 파일 또는 불일치가 있을 때 다음과 같은 항목이 geo.log에 나타날 수 있습니다. "primary_missing_file" : true 필드에 주목하세요:

{
   "bytes_downloaded" : 0,
   "class" : "Geo::BlobDownloadService",
   "correlation_id" : "01JT69C1ECRBEMZHA60E5SAX8E",
   "download_success" : false,
   "download_time_s" : 0.196,
   "gitlab_host" : "gitlab.example.com",
   "mark_as_synced" : false,
   "message" : "Blob download",
   "model_record_id" : 55,
   "primary_missing_file" : true,
   "reason" : "Not Found",
   "replicable_name" : "upload",
   "severity" : "WARN",
   "status_code" : 404,
   "time" : "2025-05-01T16:02:44.836Z",
   "url" : "http://gitlab.example.com/api/v4/geo/retrieve/upload/55"
}

동일한 오류는 특정 복제 가능 항목의 동기화 상태를 검토할 때 Admin > Geo > Sites의 UI에도 반영됩니다. 이 시나리오에서는 특정 업로드가 누락됩니다:

모든 실패 오류를 표시하는 Geo Uploads 복제 가능 대시보드.

누락된 파일 오류를 표시하는 Geo Uploads 복제 가능 대시보드.

불일치 정리#

Warning

삭제 명령을 실행하기 전에 최근의 작동하는 백업이 있는지 확인하세요.

이러한 오류를 제거하려면 먼저 어떤 특정 리소스가 영향을 받는지 식별하세요. 그런 다음 적절한 destroy 명령을 실행하여 삭제가 모든 Geo 사이트와 해당 데이터베이스에 전파되도록 합니다. 이전 시나리오를 기반으로 업로드가 이러한 오류를 일으키고 있으며 아래 예제로 사용됩니다.

  1. 식별된 불일치를 해당 Geo 모델 클래스 이름에 매핑합니다. 클래스 이름은 다음 단계에서 필요합니다. 이 시나리오에서 업로드의 경우 Upload에 해당합니다.

  2. Geo 기본 사이트에서 Rails 콘솔을 시작합니다.

  3. 이전 단계의 Geo 모델 클래스를 기반으로 누락된 파일로 인해 검증이 실패한 모든 리소스를 쿼리합니다. limit(20)을 조정하거나 제거하여 더 많은 결과를 표시합니다. 나열된 리소스가 UI에 표시된 실패한 리소스와 일치해야 함을 확인하세요:

    Upload.verification_failed.where("verification_failure like '%File is not checksummable%'").limit(20)
    
    => #
    
  4. 선택적으로, 영향받은 리소스의 id를 사용하여 아직 필요한지 확인합니다:

    Upload.find(55)
    
    => #
    
    • 영향받은 리소스를 복구해야 한다고 판단되면 다음 옵션(비망라적)을 탐색하여 복구할 수 있습니다:
      • 보조 사이트에 오브젝트가 있는지 확인하고 기본 사이트로 수동으로 복사합니다.
      • 이전 백업을 통해 오브젝트를 기본 사이트로 수동으로 다시 복사합니다.
      • 몇 가지를 샘플로 확인하여 레코드를 삭제하는 것이 괜찮다고 판단합니다. 예를 들어 모두 매우 오래된 아티팩트라면 중요한 데이터가 아닐 수 있습니다.
  5. 식별된 리소스의 id를 사용하여 destroy로 개별 또는 대량으로 적절히 삭제합니다. 적절한 Geo 모델 클래스 이름을 사용하세요.

    • 개별 리소스 삭제:

      Upload.find(55).destroy
      
    • 영향받은 모든 리소스 삭제:

      def destroy_uploads_not_checksummable
        uploads = Upload.verification_failed.where("verification_failure like '%File is not checksummable%'");1
        puts "Found #{uploads.count} resources that failed verification with 'File is not checksummable'."
        puts "Enter 'y' to continue: "
        prompt = STDIN.gets.chomp
        if prompt != 'y'
          puts "Exiting without action..."
          return
        end
      
        puts "Destroying all..."
        uploads.destroy_all
      end
      
      destroy_uploads_not_checksummable
      

모든 영향받은 리소스와 Geo 데이터 유형에 대해 단계를 반복합니다.

메시지: "Error during verification","error":"File is not checksummable"#

오류 "Error during verification","error":"File is not checksummable"는 기본 사이트의 불일치로 인해 발생합니다. GitLab 18.9부터 오류 메시지에 원인에 대한 추가 세부 정보가 포함됩니다:

  • File is not checksummable - file does not exist at: <path>: 파일이 스토리지에 없습니다. 표시된 경로가 누락된 파일을 식별하는 데 도움이 됩니다.
  • File is not checksummable - is excluded from verification: 레코드가 검증 범위에서 제외됩니다.

Geo 기본 사이트에서 파일 누락에 제공된 지침을 따르세요.

기본 Geo 사이트에서 업로드 검증 실패#

verification_checksum = nil이고 verification_failureError during verification: undefined method `underscore' for NilClass:Class 또는 The model which owns this Upload is missing.가 포함된 경우 기본 Geo 사이트에서 일부 업로드 검증이 실패하는 것은 고아 업로드(orphaned Uploads)로 인한 것입니다. 업로드를 소유하는 상위 레코드(업로드의 "모델")가 어떤 이유로 삭제됐지만 Upload 레코드는 여전히 존재합니다. 이는 일반적으로 "모델"의 대량 삭제를 구현하면서 연관된 Upload 레코드의 대량 삭제를 잊어버리는 애플리케이션 버그로 인한 것입니다. 따라서 이러한 검증 실패는 실제 검증 실패가 아니라 Postgres의 잘못된 데이터로 인한 오류입니다.

기본 Geo 사이트geo.log 파일에서 이러한 오류를 찾을 수 있습니다.

모델 레코드가 누락됐는지 확인하려면 기본 Geo 사이트에서 Rake 작업을 실행할 수 있습니다:

sudo gitlab-rake gitlab:uploads:check

Rails 콘솔에서 다음 스크립트를 실행하여 기본 Geo 사이트에서 이러한 Upload 레코드를 삭제하고 이러한 실패를 제거할 수 있습니다:

def delete_orphaned_uploads(dry_run: true)
  if dry_run
    p "This is a dry run. Upload rows will only be printed."
  else
    p "This is NOT A DRY RUN! Upload rows will be deleted from the DB!"
  end

  subquery = Geo::UploadState.where("(verification_failure LIKE 'Error during verification: The model which owns this Upload is missing.%' OR verification_failure = 'Error during verification: undefined method `underscore'' for NilClass:Class') AND verification_checksum IS NULL")
  uploads = Upload.where(upload_state: subquery)
  p "Found #{uploads.count} uploads with a model that does not exist"

  uploads_deleted = 0
  begin
    uploads.each do |upload|

      if dry_run
        p upload
      else
        uploads_deleted=uploads_deleted + 1
        p upload.destroy!
      end
    rescue => e
      puts "checking upload #{upload.id} failed with #{e.message}"
    end
  end

  p "#{uploads_deleted} remote objects were destroyed." unless dry_run
end

이전 스크립트는 delete_orphaned_uploads라는 메서드를 정의합니다. 드라이 런을 수행하려면 다음과 같이 호출합니다:

delete_orphaned_uploads(dry_run: true)

실제로 고아 업로드 행을 삭제하려면:

delete_orphaned_uploads(dry_run: false)

저장소 동기화를 차단하는 고아 전용 임대 키#

전용 임대 키가 고아가 되면 저장소 동기화가 차단되어 최대 8시간 동안 동기화 작업이 방지될 수 있습니다.

증상:

  • 저장소 동기화 차단: 영향받은 저장소의 복제 상태가 pendingfailed 상태 사이를 왔다갔다합니다.
  • geo.log에서 "Cannot obtain an exclusive lease" 메시지가 있는 로그 라인이 증가합니다.
  • 영향받은 저장소에 대해 활성 동기화 작업이 실행되지 않습니다.
  • 임대가 만료될 때까지 최대 8시간 동안 단일 저장소에 영향을 미칩니다.

진단:

  1. Geo 관리자 인터페이스를 확인하여 저장소가 활성 동기화 중이 아님을 확인합니다.

  2. geo.log에서 "Cannot obtain an exclusive lease" 메시지 수가 증가했는지 확인합니다:

    grep "Cannot obtain an exclusive lease" /var/log/gitlab/geo/geo.log
    
  3. 이러한 모든 로그 라인에 geo_sync_ssf_service:project_repository:<repository id> 값의 lease_key 필드가 포함되는지 확인합니다. 여기서 <repository id>는 영향받은 저장소의 고유 ID입니다.

  4. Sidekiq에서 영향받은 저장소에 대한 활성 동기화 작업이 실행 중이 아님을 확인합니다.

해결 방법:

Warning

권장 접근 방식은 8시간 임대 만료를 기다리는 것입니다. 수동 임대 해제는 활성 동기화 작업이 실행되지 않음을 확인했고 즉각적인 동기화가 중요한 경우에만 사용해야 합니다.

고아 임대 키를 수동으로 해제하려면:

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 영향받은 저장소의 프로젝트 ID를 찾습니다(<project-path>를 실제 프로젝트 경로로 교체):

    project = Project.find_by_full_path('<project-path>')
    project_id = project.id
    
  3. 동일한 세션에서 고아 임대를 해제합니다:

    replicator = Geo::ProjectRepositoryRegistry.find_by(project_id: project_id).replicator
    sync_service = Geo::FrameworkRepositorySyncService.new(replicator)
    uuid = Gitlab::ExclusiveLease.get_uuid(sync_service.lease_key)
    
    if uuid
      Gitlab::ExclusiveLease.cancel(sync_service.lease_key, uuid)
      puts "Lease released for project ID #{project_id}"
    else
      puts "No active lease found for project ID #{project_id}"
    end
    
  4. 임대가 해제됐는지 확인하고 새 동기화를 트리거합니다:

    replicator.sync
    
Note

임대 해제 후 저장소 동기화는 일반 Geo 동기화 일정에 따라 재시도됩니다. 또는 위와 같이 동기화를 수동으로 트리거할 수 있습니다.

오류: Error syncing repository: 13:fatal: could not read Username#

last_sync_failure 오류 Error syncing repository: 13:fatal: could not read Username for 'https://gitlab.example.com': terminal prompts disabled는 Geo 클론 또는 페치 요청 중에 JWT 인증이 실패하고 있음을 나타냅니다.

먼저 시스템 시계가 동기화됐는지 확인합니다. 상태 확인 Rake 작업을 실행하거나 보조 사이트의 모든 Sidekiq 노드와 기본 사이트의 모든 Puma 노드에서 date가 동일한지 수동으로 확인합니다.

시스템 시계가 동기화됐다면 JWT 토큰이 Git 페치가 두 개의 별도 HTTP 요청 사이에 계산을 수행하는 동안 만료될 수 있습니다. GitLab 17.1.0, 17.0.5, 16.11.7에서 수정될 때까지 모든 GitLab 버전에 존재했던 이슈 464101을 참조하세요.

이 문제를 경험하고 있는지 확인하려면:

  1. Rails 콘솔에서 코드를 몽키 패치하여 토큰 유효 기간을 1분에서 10분으로 늘립니다. 보조 사이트의 Rails 콘솔에서 실행합니다:

    module Gitlab; module Geo; class BaseRequest
      private
      def geo_auth_token(message)
        signed_data = Gitlab::Geo::SignedData.new(geo_node: requesting_node, validity_period: 10.minutes).sign_and_encode_data(message)
    
        "#{GITLAB_GEO_AUTH_TOKEN_TYPE} #{signed_data}"
      end
    end;end;end
    
  2. 동일한 Rails 콘솔에서 영향받은 프로젝트를 재동기화합니다:

    Project.find_by_full_path('<mygroup/mysubgroup/myproject>').replicator.resync
    
  3. 동기화 상태를 확인합니다:

    Project.find_by_full_path('<mygroup/mysubgroup/myproject>').replicator.registry
    
  4. last_sync_failure에 더 이상 fatal: could not read Username 오류가 포함되지 않으면 이 문제의 영향을 받고 있는 것입니다. 상태가 이제 2이어야 하며, 이는 동기화됐다는 것을 의미합니다. 그렇다면 수정이 포함된 GitLab 버전으로 업그레이드해야 합니다. 이 문제의 심각성을 줄일 수 있었을 이슈 466681에 투표하거나 댓글을 달 수도 있습니다.

이 문제를 해결하려면 보조 사이트의 모든 Sidekiq 노드를 핫 패치하여 JWT 만료 시간을 연장해야 합니다:

  1. /opt/gitlab/embedded/service/gitlab-rails/ee/lib/gitlab/geo/signed_data.rb를 편집합니다.

  2. Gitlab::Geo::SignedData.new(geo_node: requesting_node)를 찾아 , validity_period: 10.minutes를 추가합니다:

    - Gitlab::Geo::SignedData.new(geo_node: requesting_node)
    + Gitlab::Geo::SignedData.new(geo_node: requesting_node, validity_period: 10.minutes)
    
  3. Sidekiq를 재시작합니다:

    sudo gitlab-ctl restart sidekiq
    
  4. 수정이 포함된 버전으로 업그레이드하지 않는 한 모든 GitLab 업그레이드 후에 이 해결 방법을 반복해야 합니다.

오류: Error syncing repository: 13:creating repository: cloning repository: exit status 128#

성공적으로 동기화되지 않는 프로젝트에서 이 오류가 발생할 수 있습니다.

저장소 생성 중 종료 코드 128은 Git이 클론하는 동안 치명적인 오류를 발생시켰음을 의미합니다. 이는 저장소 손상, 네트워크 문제, 인증 문제, 리소스 한계 또는 프로젝트에 연관된 Git 저장소가 없어서 발생할 수 있습니다. 이러한 실패의 구체적인 원인에 대한 자세한 내용은 Gitaly 로그에서 찾을 수 있습니다.

시작 위치가 불확실한 경우 커맨드 라인에서 git fsck 명령을 수동으로 실행하여 기본 사이트의 소스 저장소에 대한 무결성 검사를 실행합니다.

오류: gitmodulesUrl: disallowed submodule url#

일부 프로젝트 저장소가 Error syncing repository: 13:creating repository: cloning repository: exit status 128 오류로 지속적으로 동기화에 실패합니다. 그러나 일부 저장소의 경우 Gitaly 로그의 구체적인 오류 메시지가 다릅니다: gitmodulesUrl: disallowed submodule url. 이 실패는 저장소에 .gitmodules 파일에 잘못된 서브모듈 URL이 포함될 때 발생합니다.

근본 원인: 이 문제는 .gitmodules 파일에 잘못된 형식의 URL이 포함된 Git 저장소의 이전 커밋으로 인해 발생합니다. 이 문제는 Geo가 기본 사이트에서 보조 사이트로 저장소를 클론하려고 할 때 실행되는 Git의 일관성 검사(git fsck) 중에 발생합니다.

문제는 저장소의 커밋 히스토리에 있습니다. .gitmodules 파일의 서브모듈 URL에 경로에 / 대신 : 를 사용하는 잘못된 형식이 포함됩니다:

  • 잘못된 형식: https://example.gitlab.com:group/project.git
  • 올바른 형식: https://example.gitlab.com/group/project.git

Geo 동기화가 실패하는 이유:

  1. Git의 엄격한 유효성 검사: GitLab 17.0 및 최신 Git 버전부터 Git은 클론 작업 중에 더 엄격한 fsck 검사를 수행합니다.
  2. 이전 데이터 유지: 현재 .gitmodules 파일이 올바르더라도 Git은 모든 이전 버전을 저장소의 "Blob"으로 저장합니다.
  3. 클론 시 실패: Geo가 저장소를 클론하려고 할 때 Git의 fsck모든 오브젝트(이전 것 포함)를 검사하고 잘못된 형식의 URL을 발견하면 실패합니다.
  4. 완전한 동기화 실패: 전체 클론 작업이 실패하여 저장소가 보조 사이트에 도달하지 못하게 됩니다.

중요: 현재 .gitmodules 파일을 편집해도 이 문제가 해결되지 않습니다. 왜냐하면 문제가 있는 데이터는 파일의 현재 버전이 아닌 저장소의 Git 히스토리에 존재하기 때문입니다.

이 문제는 GitLab 17.0 이상에서 알려져 있으며, 더 엄격한 저장소 일관성 검사의 결과입니다. 이 새로운 동작은 이 검사가 추가된 Git 자체의 변경으로 인한 것입니다. GitLab Geo 또는 Gitaly에 국한된 것이 아닙니다. 자세한 내용은 이슈 468560을 참조하세요.

해결 방법#

  1. 프로젝트 백업

    계속하기 전에 프로젝트 내보내기 옵션을 사용하여 프로젝트를 미리 백업하세요.

  2. 문제가 있는 Blob ID 식별

    영향받은 각 프로젝트에 대해 다음 방법 중 하나를 사용하여 문제가 있는 Blob ID를 식별합니다:

    • git fsck 사용: 저장소를 클론한 후 git fsck를 실행하여 문제를 확인합니다:

      git clone https://example.gitlab.com/group/project.git
      cd project
      git fsck
      

      출력은 문제가 있는 Blob을 보여줍니다:

      Checking object directories: 100% (256/256), done.
      error in blob : gitmodulesUrl: disallowed submodule url: https://example.gitlab.com:group/project.git
      Checking objects: 100% (12/12), done.
      
    • Gitaly 로그를 확인합니다. 특정 Blob SHA를 찾기 위해 gitmodulesUrl이 포함된 오류 메시지를 찾습니다.

  3. Blob 제거

    영향받은 각 프로젝트에 대해 이전 단계에서 식별된 문제가 있는 Blob ID를 제거합니다.

    중요한 제한 사항: 이러한 저장소 중 하나라도 포크 네트워크의 일부라면 Blob 제거 방법이 작동하지 않을 수 있습니다(오브젝트 풀에 포함된 Blob은 이 방법으로 제거할 수 없음).

  4. 필요한 경우 .gitmodules 잘못된 URL 수정

    영향받은 각 저장소의 .gitmodules 파일 상태를 확인합니다.

    .gitmodules에 여전히 https://example.gitlab.com/foo/bar.git 대신 https://example.gitlab.com:foo/bar.git와 같은 잘못된 URL이 포함되어 있으면:

    • .gitmodules 파일에서 URL을 수정합니다.
    • 유효한 URL로 커밋을 푸시합니다.
Warning

수정 후, 영향받은 프로젝트에서 작업하는 모든 개발자는 현재 로컬 복사본을 제거하고 새 저장소를 클론해야 합니다. 그렇지 않으면 변경 사항을 푸시할 때 문제가 있는 Blob을 다시 도입할 수 있습니다.

오류: 정확히 3시간에 fetch remote: signal: terminated: context deadline exceeded#

Git 저장소를 동기화하는 동안 정확히 3시간에 Git 페치가 실패하는 경우:

  1. /etc/gitlab/gitlab.rb를 편집하여 기본값 10800초에서 Git 시간 초과를 늘립니다:

    # Git timeout in seconds
    gitlab_rails['gitlab_shell_git_timeout'] = 21600
    
  2. GitLab을 재구성합니다:

    sudo gitlab-ctl reconfigure
    

보조 사이트에서 레지스트리 복제 구성 시 오류 Failed to open TCP connection to localhost:5000#

보조 사이트에서 컨테이너 레지스트리 복제를 구성할 때 다음 오류가 발생할 수 있습니다:

Failed to open TCP connection to localhost:5000 (Connection refused - connect(2) for \"localhost\" port 5000)"

보조 사이트에서 컨테이너 레지스트리가 활성화되지 않은 경우 이 문제가 발생합니다. 이를 수정하려면 컨테이너 레지스트리가 보조 사이트에서 활성화됐는지 확인합니다. Let's Encrypt 통합이 비활성화된 경우 컨테이너 레지스트리도 비활성화되므로 자체 도메인에서 수동으로 구성해야 합니다.

오류: Verification timed out after 28800#

가능한 근본 원인: 다양한 레지스트리 유형에서 검증 충돌을 일으키는 중복 레지스트리 레코드.

진단:

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 여러 유형에서 중복 레지스트리를 확인합니다:

    # Check for duplicate upload registries
    upload_ids = Geo::UploadRegistry.group(:file_id).having('COUNT(*) > 1').pluck(:file_id)
    puts "Duplicate upload IDs count: #{upload_ids.size}"
    puts 'Duplicate Upload IDs:', upload_ids
    
    # Check for duplicate job artifact registries
    artifact_ids = Geo::JobArtifactRegistry.group(:artifact_id).having('COUNT(*) > 1').pluck(:artifact_id)
    puts "Duplicate artifact IDs count: #{artifact_ids.size}"
    puts 'Duplicate Artifact IDs:', artifact_ids
    
    # Check for duplicate package file registries
    package_file_ids = Geo::PackageFileRegistry.group(:package_file_id).having('COUNT(*) > 1').pluck(:package_file_id)
    puts "Duplicate package file IDs count: #{package_file_ids.size}"
    puts 'Duplicate Package File IDs:', package_file_ids
    
    # Check for duplicate LFS object registries
    lfs_object_ids = Geo::LfsObjectRegistry.group(:lfs_object_id).having('COUNT(*) > 1').pluck(:lfs_object_id)
    puts "Duplicate LFS object IDs count: #{lfs_object_ids.size}"
    puts 'Duplicate LFS Object IDs:', lfs_object_ids
    
    # Check for duplicate pages deployment registries
    pages_deployment_ids = Geo::PagesDeploymentRegistry.group(:pages_deployment_id).having('COUNT(*) > 1').pluck(:pages_deployment_id)
    puts "Duplicate pages deployment IDs count: #{pages_deployment_ids.size}"
    puts 'Duplicate Pages Deployment IDs:', pages_deployment_ids
    
    # Check for duplicate terraform state version registries
    terraform_state_ids = Geo::TerraformStateVersionRegistry.group(:terraform_state_version_id).having('COUNT(*) > 1').pluck(:terraform_state_version_id)
    puts "Duplicate terraform state version IDs count: #{terraform_state_ids.size}"
    puts 'Duplicate Terraform State Version IDs:', terraform_state_ids
    

해결:

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 영향받은 각 유형에 대한 중복 레지스트리 항목을 제거합니다:

    # Remove duplicate upload registries
    upload_ids = Geo::UploadRegistry.group(:file_id).having('COUNT(*) > 1').pluck(:file_id)
    if upload_ids.any?
      Geo::UploadRegistry.where(file_id: upload_ids).delete_all
      puts "Removed #{upload_ids.size} duplicate upload registry entries"
    end
    
    # Remove duplicate job artifact registries
    artifact_ids = Geo::JobArtifactRegistry.group(:artifact_id).having('COUNT(*) > 1').pluck(:artifact_id)
    if artifact_ids.any?
      Geo::JobArtifactRegistry.where(artifact_id: artifact_ids).delete_all
      puts "Removed #{artifact_ids.size} duplicate job artifact registry entries"
    end
    
    # Remove duplicate package file registries
    package_file_ids = Geo::PackageFileRegistry.group(:package_file_id).having('COUNT(*) > 1').pluck(:package_file_id)
    if package_file_ids.any?
      Geo::PackageFileRegistry.where(package_file_id: package_file_ids).delete_all
      puts "Removed #{package_file_ids.size} duplicate package file registry entries"
    end
    
    # Remove duplicate LFS object registries
    lfs_object_ids = Geo::LfsObjectRegistry.group(:lfs_object_id).having('COUNT(*) > 1').pluck(:lfs_object_id)
    if lfs_object_ids.any?
      Geo::LfsObjectRegistry.where(lfs_object_id: lfs_object_ids).delete_all
      puts "Removed #{lfs_object_ids.size} duplicate LFS object registry entries"
    end
    
    # Remove duplicate pages deployment registries
    pages_deployment_ids = Geo::PagesDeploymentRegistry.group(:pages_deployment_id).having('COUNT(*) > 1').pluck(:pages_deployment_id)
    if pages_deployment_ids.any?
      Geo::PagesDeploymentRegistry.where(pages_deployment_id: pages_deployment_ids).delete_all
      puts "Removed #{pages_deployment_ids.size} duplicate pages deployment registry entries"
    end
    
    # Remove duplicate terraform state version registries
    terraform_state_ids = Geo::TerraformStateVersionRegistry.group(:terraform_state_version_id).having('COUNT(*) > 1').pluck(:terraform_state_version_id)
    if terraform_state_ids.any?
      Geo::TerraformStateVersionRegistry.where(terraform_state_version_id: terraform_state_ids).delete_all
      puts "Removed #{terraform_state_ids.size} duplicate terraform state version registry entries"
    end
    
  3. 모든 레지스트리 유형에서 정리를 확인합니다:

    # Verify no remaining duplicates
    upload_duplicates = Geo::UploadRegistry.group(:file_id).having('COUNT(*) > 1').count
    artifact_duplicates = Geo::JobArtifactRegistry.group(:artifact_id).having('COUNT(*) > 1').count
    package_duplicates = Geo::PackageFileRegistry.group(:package_file_id).having('COUNT(*) > 1').count
    lfs_duplicates = Geo::LfsObjectRegistry.group(:lfs_object_id).having('COUNT(*) > 1').count
    pages_duplicates = Geo::PagesDeploymentRegistry.group(:pages_deployment_id).having('COUNT(*) > 1').count
    terraform_duplicates = Geo::TerraformStateVersionRegistry.group(:terraform_state_version_id).having('COUNT(*) > 1').count
    
    puts "Remaining duplicates:"
    puts "  Uploads: #{upload_duplicates.size}"
    puts "  Job Artifacts: #{artifact_duplicates.size}"
    puts "  Package Files: #{package_duplicates.size}"
    puts "  LFS Objects: #{lfs_duplicates.size}"
    puts "  Pages Deployments: #{pages_duplicates.size}"
    puts "  Terraform State Versions: #{terraform_duplicates.size}"
    

오류: Checksum does not match the primary checksum#

가능한 근본 원인: 저장소 또는 컨테이너 레지스트리 검증 간격 변경으로 인한 체크섬 불일치.

진단:

  1. 보조 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 실패한 저장소 또는 컨테이너 레지스트리를 확인합니다:

    failed_repos = Geo::ProjectRepositoryRegistry.failed.limit(100)
    failed_repos.each do |repo|
      puts "Project ID: #{repo.project_id}"
      puts "Primary checksum: #{repo.verification_checksum_mismatched}"
      puts "Secondary checksum: #{repo.verification_checksum}"
      puts "Error: #{repo.last_sync_failure}"
      puts "---"
    end
    
    failed_container_repos = Geo::ContainerRepositoryRegistry.failed.limit(100)
    failed_container_repos.each do |repo|
      puts "Container Repo Id: #{repo.model_record_id}"
      puts "Primary checksum: #{repo.verification_checksum_mismatched}"
      puts "Secondary checksum: #{repo.verification_checksum}"
      puts "Error: #{repo.last_sync_failure}"
      puts "---"
    end
    

해결:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 특정 프로젝트 또는 컨테이너 레지스트리에 대한 재검증을 강제합니다:

    project_ids = [1, 2, 3] # Replace with actual failing project IDs
    
    project_ids.each do |project_id|
      project = Project.find(project_id)
      puts "Reverifying project: #{project.full_path}"
    
      project_state = project.project_state
      project_state.update!(verification_state: 0)
    
      puts "Project #{project_id} marked for reverification"
    end
    
    container_repo_ids = [1, 2, 3]
    
    container_repo_ids.each do |repo_id|
      container_repo = ContainerRepository.find(repo_id)
      puts "Reverifying container repository: #{container_repo.path}"
    
      state = container_repo.container_repository_state
      state.update!(verification_state: 0)
    
      puts "Container Repo #{repo_id} marked for reverification"
    end
    

Error during verification: File is not checksummable에 대한 오브젝트 유형별 트러블슈팅#

Geo 데이터 유형마다 고유한 특성과 일반적인 실패 패턴이 있습니다. 이 섹션에서는 특정 오브젝트 유형에 대한 대상화된 트러블슈팅을 제공합니다.

업로드#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 업로드를 식별합니다:

    checksummable_failures = Upload.verification_failed
                                    .where("verification_failure LIKE '%File is not checksummable%'")
    
    puts "Found #{checksummable_failures.count} uploads with missing files"
    
    # Adjust 'limit' to count
    checksummable_failures.limit(5).each_with_index do |record, index|
      puts "Record #{index + 1}:"
      puts "  ID: #{record.id}"
      puts "  Path: #{record.path}"
      puts "  Model: #{record.model_type} (ID: #{record.model_id})"
      puts "  Created: #{record.created_at}"
      puts "---"
    end
    

해결:

Warning

업로드 레코드를 삭제하기 전에 최근의 작동하는 백업이 있는지 확인하세요. 팀과 협력하여 이러한 업로드를 제거해도 안전한지 확인하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 확인 후 문제가 있는 업로드를 제거합니다:

    # Remove individual upload
    Upload.find(55).destroy
    
    # Or remove all uploads with missing files (use with extreme caution)
    Upload.verification_failed.where("verification_failure LIKE '%File is not checksummable%'").destroy_all
    

페이지 배포#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 문제가 있는 페이지 배포를 검사합니다:

    checksummable_failures = PagesDeployment.verification_failed
                                            .where("verification_failure LIKE '%File is not checksummable%'")
    
    checksummable_failures.each_with_index do |record, index|
      puts "Record #{index + 1}:"
      puts "  ID: #{record.id}"
      puts "  Project: #{record.project.full_path}"
      puts "  Created: #{record.created_at}"
      puts "  File exists: #{record.file.exists?}"
      puts "---"
    end
    

해결:

Warning

페이지 배포 레코드를 삭제하기 전에 최근의 작동하는 백업이 있는지 확인하세요. 팀과 협력하여 이러한 배포를 제거해도 안전한지 확인하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 팀과 협력하여 배포를 제거해도 안전하다고 확인한 후:

    failed_ids = [21875, 21907, 21992] # Replace with actual IDs
    PagesDeployment.where(id: failed_ids).destroy_all
    puts "Removed #{failed_ids.size} problematic pages deployments"
    

LFS 오브젝트#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 문제가 있는 LFS 오브젝트를 검사합니다:

    checksummable_failures = LfsObject.verification_failed
                                      .where("verification_failure LIKE '%File is not checksummable%'")
    
    checksummable_failures.each_with_index do |record, index|
      puts "Record #{index + 1}:"
      puts "  OID: #{record.oid}"
      puts "  Size: #{record.size} bytes"
      puts "  File Store: #{record.file_store}"
      puts "  Created: #{record.created_at}"
    
      # Show associated projects
      associations = record.lfs_objects_projects.includes(:project)
      puts "  Associated projects (#{associations.count}):"
      associations.each do |assoc|
        project = assoc.project
        if project
          puts "    - #{project.full_path}"
        else
          puts "    - Project ID: #{assoc.project_id} (not found)"
        end
      end
      puts "---"
    end
    

해결:

Warning

LFS 오브젝트를 제거하면 해당 오브젝트를 참조하는 모든 프로젝트에 영향을 미칩니다. 삭제하기 전에 백업을 확보하고 프로젝트 관리자와 협력하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 LFS 오브젝트를 제거합니다:

    def destroy_lfs_not_checksummable(dry_run: true)
      lfs_objects = LfsObject.verification_failed.where("verification_failure like '%File is not checksummable%'")
      puts "Found #{lfs_objects.count} LFS objects that failed verification with 'File is not checksummable'."
    
      if dry_run
        puts "DRY RUN - No changes made"
        lfs_objects.each { |obj| puts "Would remove: OID #{obj.oid}, Size: #{obj.size}" }
        return
      end
    
      puts "Enter 'y' to continue with deletion: "
      prompt = STDIN.gets.chomp
      if prompt != 'y'
        puts "Exiting without action..."
        return
      end
    
      puts "Destroying all..."
      lfs_objects.each do |lfs_object|
        lfs_object.lfs_objects_projects.destroy_all
        lfs_object.destroy!
      end
      puts "Done!"
    end
    
    # Run in dry run mode first
    destroy_lfs_not_checksummable(dry_run: true)
    

작업 아티팩트#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 아티팩트를 확인합니다:

    failed_artifacts = Ci::JobArtifact.verification_failed.where("verification_failure LIKE '%File is not checksummable%'")
    
    failed_artifacts.each do |registry|
      artifact = Ci::JobArtifact.find_by(id: registry.id)
      if artifact
        puts "Artifact ID: #{artifact.id}"
        puts "Job ID: #{artifact.job_id}"
        puts "Project ID: #{artifact.project_id}"
        puts "File exists: #{artifact.file.exists?}"
        puts "File path: #{artifact.file.path}"
      else
        puts "Artifact ID #{artifact.id} not found in database"
      end
      puts "---"
    end
    

해결:

Warning

작업 아티팩트 레코드를 삭제하기 전에 최근의 작동하는 백업이 있는지 확인하세요. 팀과 협력하여 이러한 아티팩트를 제거해도 안전한지 확인하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 아티팩트를 정리합니다:

    def cleanup_missing_artifacts(dry_run: true)
      missing_file_artifacts = []
    
      Ci::JobArtifact.find_each do |artifact|
        unless artifact.file.exists?
          missing_file_artifacts << artifact.id
          puts "Missing file for artifact #{artifact.id}" if dry_run
        end
      end
    
      puts "Found #{missing_file_artifacts.size} artifacts with missing files"
    
      unless dry_run
        Ci::JobArtifact.where(id: missing_file_artifacts).destroy_all
        puts "Removed #{missing_file_artifacts.size} artifacts with missing files"
      end
    end
    
    # Run in dry run mode first
    cleanup_missing_artifacts(dry_run: true)
    

파이프라인 아티팩트#

진단:

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 아티팩트를 확인합니다:

    failed_pipeline_artifacts = Ci::PipelineArtifact.verification_failed.where("verification_failure LIKE '%checksummable%'")
    
    failed_pipeline_artifacts.each do |registry|
      artifact = Ci::PipelineArtifact.find_by(id: registry.id)
      if artifact
        puts "Artifact ID: #{artifact.id}"
        puts "Pipeline ID: #{artifact.pipeline_id}"
        puts "Project ID: #{artifact.project_id}"
        puts "File exists: #{artifact.file.exists?}"
        puts "File path: #{artifact.file.path}"
      else
        puts "Artifact ID #{artifact.id} not found in database"
      end
      puts "---"
    end
    

해결:

Warning

파이프라인 아티팩트 레코드를 삭제하기 전에 최근의 작동하는 백업이 있는지 확인하세요. 팀과 협력하여 이러한 아티팩트를 제거해도 안전한지 확인하세요.

  1. 기본 사이트에서 Rails 콘솔 세션을 시작합니다.

  2. 누락된 파일이 있는 파이프라인 아티팩트를 제거합니다:

    def destroy_pipeline_artifacts_not_checksummable
      artifacts = Ci::PipelineArtifact.verification_failed.where("verification_failure like '%File is not checksummable%'")
      puts "Found #{artifacts.count} pipeline artifacts that failed verification with 'File is not checksummable'."
      puts "Enter 'y' to continue: "
      prompt = STDIN.gets.chomp
      if prompt != 'y'
        puts "Exiting without action..."
        return
      end
    
      puts "Destroying all..."
      artifacts.destroy_all
      puts "Done!"
    end
    
    destroy_pipeline_artifacts_not_checksummable
    

오류: Projects - Error during verification: Repository does not exist#

근본 원인: Git 저장소가 없는 프로젝트로 인한 검증 실패.

증상:

  • 검증 중에 프로젝트에 "Repository does not exist" 오류가 표시됩니다.
  • 합법적으로 저장소가 없는 프로젝트에 대한 Geo UI에서 잘못된 오류 보고.
  • 존재하지 않는 저장소에 대한 낭비적인 동기화 시도.

해결 방법:

존재하지 않는 경우 기본 사이트에서 프로젝트 저장소를 생성합니다:

puts "Found #{Project.verification_failed.count} project repos failed to checksum"
Project.verification_failed.find_each do |p|
  puts "#{p.full_path} #{p.ensure_repository.inspect}"
end

오류: Expected(200) <=> Actual(403 Forbidden)#

근본 원인: ListBucket 권한 누락으로 인해 S3 API가 404 대신 403을 반환합니다.

증상:

  • S3 엔드포인트가 있는 로그에 403 오류가 발생합니다.
  • S3 버킷에 대한 HEAD 요청이 실패합니다.
  • 오브젝트 스토리지 지원 데이터 유형에 대한 동기화 실패.

해결:

이를 위해서는 GitLab에서 사용하는 S3 IAM 정책에 ListBucket 권한을 추가하기 위한 인프라 팀 개입이 필요합니다.

메시지: Synchronization failed - Error syncing repository#

Warning

이 문제의 영향을 받는 대형 저장소의 경우 재동기화에 오랜 시간이 걸릴 수 있으며 Geo 사이트, 스토리지 및 네트워크 시스템에 상당한 부하를 줄 수 있습니다.

다음 오류 메시지는 저장소 동기화 시 일관성 검사 오류를 나타냅니다:

Synchronization failed - Error syncing repository [..] fatal: fsck error in packed object

이 오류를 트리거하는 여러 문제가 있습니다. 예를 들어, 이메일 주소 문제:

Error syncing repository: 13:fetch remote: "error: object : badEmail: invalid author/committer line - bad email
   fatal: fsck error in packed object
   fatal: fetch-pack: invalid index-pack output

이 오류를 트리거하는 또 다른 문제는 object : hasDotgit: contains '.git'입니다. 모든 저장소에 여러 문제가 있을 수 있으므로 특정 오류를 확인하세요.

두 번째 동기화 오류는 저장소 확인 문제로 인해 발생할 수도 있습니다:

Error syncing repository: 13:Received RST_STREAM with error code 2.

이러한 오류는 실패한 모든 저장소를 즉시 동기화하여 관찰할 수 있습니다.

일관성 오류를 일으키는 잘못된 형식의 오브젝트를 제거하려면 저장소 히스토리를 다시 작성해야 하며, 이는 일반적으로 선택 사항이 아닙니다.

이러한 일관성 검사를 무시하려면 보조 Geo 사이트의 Gitaly를 재구성하여 이러한 git fsck 문제를 무시하도록 합니다. 다음 구성 예제:

Gitaly 문서에 더 많은 세부 정보가 있으며, 다른 Git 검사 실패 및 이전 GitLab 버전에 대한 정보가 포함됩니다.

gitaly['configuration'] = {
  git: {
    config: [
      { key: "fsck.duplicateEntries", value: "ignore" },
      { key: "fsck.badFilemode", value: "ignore" },
      { key: "fsck.missingEmail", value: "ignore" },
      { key: "fsck.badEmail", value: "ignore" },
      { key: "fsck.hasDotgit", value: "ignore" },
      { key: "fetch.fsck.duplicateEntries", value: "ignore" },
      { key: "fetch.fsck.badFilemode", value: "ignore" },
      { key: "fetch.fsck.missingEmail", value: "ignore" },
      { key: "fetch.fsck.badEmail", value: "ignore" },
      { key: "fetch.fsck.hasDotgit", value: "ignore" },
      { key: "receive.fsck.duplicateEntries", value: "ignore" },
      { key: "receive.fsck.badFilemode", value: "ignore" },
      { key: "receive.fsck.missingEmail", value: "ignore" },
      { key: "receive.fsck.badEmail", value: "ignore" },
      { key: "receive.fsck.hasDotgit", value: "ignore" },
    ],
  },
}

fsck 오류의 포괄적인 목록은 Git 문서에서 찾을 수 있습니다.

GitLab 16.1 이상에서는 이러한 문제 중 일부를 해결할 수 있는 향상된 기능이 포함됩니다.

Gitaly 이슈 5625에서는 소스 저장소에 문제가 있는 커밋이 포함된 경우에도 Geo가 저장소를 복제하도록 제안합니다.

관련 오류 does not appear to be a git repository#

Synchronization failed - Error syncing repository 오류 메시지와 함께 다음 로그 메시지가 표시될 수 있습니다. 이 오류는 보조 Geo 사이트의 파일 시스템에 있는 저장소의 .git/config 파일에 예상되는 Geo 원격이 없음을 나타냅니다:

{
  "created": "@1603481145.084348757",
  "description": "Error received from peer unix:/var/opt/gitlab/gitaly/gitaly.socket","grpc_message": "exit status 128",
  "grpc_status": 13
}
{"grpc.request.fullMethod": "/gitaly.RemoteService/FindRemoteRootRef",
  "grpc.request.glProjectPath": "<namespace>/<project>","level": "error",
  "msg": "fatal: 'geo' does not appear to be a git repository
          fatal: Could not read from remote repository. …",
}

이를 해결하려면:

  1. 보조 Geo 사이트의 웹 인터페이스에 로그인합니다.

  2. .git 폴더를 백업합니다.

  3. 선택적으로, 일부 ID를 샘플 확인하여 실제로 알려진 Geo 복제 실패가 있는 프로젝트에 해당하는지 확인합니다. fatal: 'geo'grep 검색어로 사용하고 다음 API 호출을 사용합니다:

    curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<first_failed_geo_sync_ID>"
    
  4. Rails 콘솔을 열고 다음을 실행합니다:

    failed_project_registries = Geo::ProjectRepositoryRegistry.failed
    
    if failed_project_registries.any?
      puts "Found #{failed_project_registries.count} failed project repository registry entries:"
    
      failed_project_registries.each do |registry|
        puts "ID: #{registry.id}, Project ID: #{registry.project_id}, Last Sync Failure: '#{registry.last_sync_failure}'"
      end
    else
      puts "No failed project repository registry entries found."
    end
    
  5. 각 프로젝트에 대한 새 동기화를 실행하기 위해 다음 명령을 실행합니다:

    failed_project_registries.each do |registry|
      registry.replicator.sync
      puts "Sync initiated for registry ID: #{registry.id}, Project ID: #{registry.project_id}"
    end
    

백필 중 실패#

백필 중 실패는 백필 큐 끝에서 재시도가 예약되므로, 이러한 실패는 백필이 완료된 후에 해결됩니다.

메시지: unexpected disconnect while reading sideband packet#

불안정한 네트워킹 조건으로 인해 기본 사이트에서 대용량 저장소 데이터를 가져오려고 할 때 Gitaly가 실패할 수 있습니다. 이러한 조건으로 인해 이 오류가 발생할 수 있습니다:

curl 18 transfer closed with outstanding read data remaining & fetch-pack:
unexpected disconnect while reading sideband packet

이 오류는 사이트 간에 저장소를 처음부터 복제해야 하는 경우 더 발생하기 쉽습니다.

Geo는 여러 번 재시도하지만 네트워크 중단으로 인해 전송이 지속적으로 중단되는 경우 rsync와 같은 대체 방법을 사용하여 git을 우회하고 Geo에서 복제에 실패하는 저장소의 초기 복사본을 만들 수 있습니다.

각 실패한 저장소를 개별적으로 전송하고 각 전송 후 일관성을 확인하는 것이 좋습니다. rsync를 다른 서버로 지침에 따라 각 영향받은 저장소를 기본 사이트에서 보조 사이트로 전송합니다.

Geo 보조 사이트에서 저장소 확인 실패 찾기#

Note

모든 저장소 데이터 유형이 GitLab 16.3의 Geo Self-Service Framework로 마이그레이션됐습니다. 이 기능을 Geo Self-Service Framework에 다시 구현하기 위한 이슈가 있습니다.

GitLab 16.2 이하의 경우:

모든 프로젝트에 대해 활성화된 경우 저장소 확인은 Geo 보조 사이트에서도 수행됩니다. 메타데이터는 Geo 추적 데이터베이스에 저장됩니다.

Geo 보조 사이트에서의 저장소 확인 실패가 반드시 복제 문제를 의미하지는 않습니다. 다음은 이러한 실패를 해결하기 위한 일반적인 접근 방식입니다.

  1. 아래에 언급된 대로 영향받은 저장소와 기록된 오류를 찾습니다.
  2. 특정 git fsck 오류를 진단하려고 합니다. 가능한 오류 범위가 넓으므로 검색 엔진에서 검색해 보세요.
  3. 영향받은 저장소의 일반적인 기능을 테스트합니다. 보조 사이트에서 Pull하고 파일을 봅니다.
  4. 기본 사이트의 저장소 복사본에 동일한 git fsck 오류가 있는지 확인합니다. 페일오버를 계획 중이라면 보조 사이트가 기본 사이트와 동일한 정보를 갖도록 우선 순위를 정하는 것을 고려하세요. 기본 사이트의 백업을 확보하고 계획된 페일오버 지침을 따르세요.
  5. 기본 사이트에 Push하고 변경 사항이 보조 사이트에 복제되는지 확인합니다.
  6. 복제가 자동으로 작동하지 않으면 저장소를 수동으로 동기화하려고 합니다.

다음 기본 트러블슈팅 단계를 수행하려면 Rails 콘솔 세션을 시작합니다.

Warning

데이터를 변경하는 명령은 올바르게 실행되지 않거나 올바른 조건에서 실행되지 않으면 손상을 일으킬 수 있습니다. 항상 먼저 테스트 환경에서 명령을 실행하고 복원 준비가 된 백업 인스턴스를 마련하세요.

저장소 확인에 실패한 저장소 수 가져오기#

Geo::ProjectRegistry.where(last_repository_check_failed: true).count

저장소 확인에 실패한 저장소 찾기#

Geo::ProjectRegistry.where(last_repository_check_failed: true)

Gitaly 클러스터에서 저장소를 강제 삭제하고 재동기화#

Warning

이 절차는 위험하고 과도합니다. 다른 트러블슈팅 방법이 실패한 경우에만 최후 수단으로 사용하세요. 이 절차는 저장소가 재동기화될 때까지 일시적인 데이터 손실을 야기합니다.

이 절차는 보조 사이트의 Gitaly 클러스터에서 저장소를 삭제하고 다시 동기화합니다. 위험을 이해하고 이러한 모든 조건이 사실인 경우에만 사용을 고려해야 합니다:

  • 기본 사이트의 저장소에 대해 git clone이 작동합니다.
  • p.replicator.sync_repository(여기서 p는 프로젝트 모델 인스턴스)가 보조 사이트에서 Gitaly 오류를 기록합니다.
  • 표준 트러블슈팅으로 문제가 해결되지 않았습니다.

전제 조건:

  • 보조 사이트의 Rails 콘솔과 Praefect 노드 모두에 대한 관리자 액세스 권한이 있는지 확인합니다.
  • 기본 사이트에서 저장소가 액세스 가능하고 올바르게 작동하는지 확인합니다.
  • 이 절차를 되돌려야 하는 경우를 위한 백업 계획을 갖추세요.

수행 방법:

  1. 보조 사이트의 Rails 콘솔에 로그인합니다.

  2. 다음 옵션 중 하나를 사용하여 프로젝트 모델을 인스턴스화하고 p 변수에 저장합니다:

    • 영향받은 프로젝트 ID(예: 60087)를 알고 있는 경우:

      p = Project.find(60087)
      
    • GitLab에서 영향받은 프로젝트 경로(예: my-group/my-project)를 알고 있는 경우:

      p = Project.find_by_full_path('my-group/my-project')
      
  3. 프로젝트 Git 저장소의 가상 스토리지를 출력하고 나중을 위해 기록합니다:

    p.repository.storage
    

    예제 출력:

    irb(main):002:0> p.repository.storage
    => "default"
    
  4. 프로젝트 Git 저장소의 상대 경로를 출력하고 나중을 위해 기록합니다:

    p.repository.disk_path + '.git'
    

    예제 출력:

    irb(main):003:0> p.repository.disk_path + '.git'
    => "@hashed/66/b2/66b2fc8562b3432399acc2d0108fcd2782b32bd31d59226c7a03a20b32c76ee8.git"
    
  5. 보조 사이트의 Praefect 노드에 SSH로 접속합니다.

  6. 이전 단계에서 기록한 가상 스토리지와 상대 경로를 사용하여 Gitaly 클러스터에서 저장소를 수동으로 제거하는 절차를 따릅니다.

    보조 사이트의 Git 저장소가 삭제됩니다.

  7. Rails 콘솔에서 재동기화하기 전에 상관 ID를 설정합니다. 이 ID는 이 세션에서 실행하는 명령과 관련된 모든 로그를 검색하는 데 도움이 됩니다:

    Gitlab::ApplicationContext.push({})
    

    예제 출력:

    [2] pry(main)> Gitlab::ApplicationContext.push({})
    => #"53da64ae800bd4794a2b61ab1c80b028"}>
    
  8. 프로젝트 Git 저장소를 동기화합니다:

    p.replicator.sync_repository
    

Git 저장소는 이제 기본 사이트에서 보조 사이트로 재동기화되어야 합니다. Geo 관리자 인터페이스를 통해 또는 Rails 콘솔에서 저장소의 동기화 상태를 확인하여 동기화 프로세스를 모니터링합니다.

인프라 및 성능 고려사항#

일부 동기화 문제는 인프라 수준 문제 또는 성능 제약으로 인해 발생합니다.

높은 동시성 문제#

과도한 Geo 검증 동시성이 데이터베이스를 압도하고 동기화 실패를 일으킬 수 있습니다.

증상:

  • 데이터베이스 연결 시간 초과
  • 데이터베이스 서버의 높은 CPU 사용량
  • 정상적인 인프라에도 불구하고 느린 동기화 진행

진단 및 해결:

기본 사이트에서 UI를 통해 동시성 설정을 줄입니다.

수동 동기화 상태 업데이트#

경우에 따라 기본 문제를 해결한 후 오브젝트 유형을 수동으로 동기화됨으로 표시해야 할 수 있습니다. 이 시나리오는 보조 사이트의 오브젝트 버킷에 파일을 수동으로 업로드하는 방법으로만 문제를 수정할 수 있을 때 발생합니다. 일반적으로 이 작업이 필요하지 않지만 버전 버그로 인해 발생할 수 있습니다. 다음은 수동으로 업로드된 오브젝트 유형(이 경우 업로드)을 동기화됨으로 표시하는 방법을 보여줍니다.

Warning

파일이 보조 사이트에 실제로 존재하고 액세스 가능한지 확인한 경우에만 오브젝트를 동기화됨으로 표시하세요.

def mark_upload_synced(upload_id)
  upload = Upload.find(upload_id)
  registry = upload.replicator.registry
  registry.start
  registry.synced!
  puts "Marked upload #{upload_id} as synced"
end

# Mark specific uploads as synced
upload_ids = [107221, 107320] # Replace with actual IDs
upload_ids.each { |id| mark_upload_synced(id) }

Geo 보조 사이트 복제 재설정#

보조 사이트가 손상된 상태에 있고 복제 상태를 처음부터 다시 시작하도록 재설정하려는 경우 도움이 될 수 있는 몇 가지 단계가 있습니다:

  1. Sidekiq와 Geo Log Cursor를 중지합니다.

    Sidekiq가 정상적으로 중지되도록 만들 수 있지만 새 작업 받기를 중지하고 현재 작업이 처리를 마칠 때까지 기다리게 합니다.

    첫 번째 단계에는 SIGTSTP 킬 신호를 보내고 모든 작업이 완료되면 SIGTERM을 보내야 합니다. 그렇지 않으면 gitlab-ctl stop 명령을 사용합니다.

    gitlab-ctl status sidekiq
    # run: sidekiq: (pid 10180) <- this is the PID you will use
    kill -TSTP 10180 # change to the correct PID
    
    gitlab-ctl stop sidekiq
    gitlab-ctl stop geo-logcursor
    

    Sidekiq 로그를 확인하여 Sidekiq 작업 처리가 완료됐는지 알 수 있습니다:

    gitlab-ctl tail sidekiq
    
  2. Gitaly 및 Gitaly 클러스터(Praefect) 데이터를 지웁니다.

   mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
   sudo gitlab-ctl reconfigure
  1. 선택적으로 Praefect 내부 로드 밸런서를 비활성화합니다.
    1. 각 Praefect 서버에서 Praefect를 중지합니다:

      sudo gitlab-ctl stop praefect
      
    2. Praefect 데이터베이스를 재설정합니다:

      sudo /opt/gitlab/embedded/bin/psql -U praefect -d template1 -h localhost -c "DROP DATABASE praefect_production WITH (FORCE);"
      sudo /opt/gitlab/embedded/bin/psql -U praefect -d template1 -h localhost -c "CREATE DATABASE praefect_production WITH OWNER=praefect ENCODING=UTF8;"
      
    3. 각 Gitaly 노드에서 저장소 데이터를 이름 변경/삭제합니다:

      sudo mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
      sudo gitlab-ctl reconfigure
      
    4. Praefect 배포 노드에서 재구성을 실행하여 데이터베이스를 설정합니다:

      sudo gitlab-ctl reconfigure
      
    5. 각 Praefect 서버에서 Praefect를 시작합니다:

      sudo gitlab-ctl start praefect
      
    6. 선택적으로 비활성화한 경우 Praefect 내부 로드 밸런서를 다시 활성화합니다.

[!note] 더 이상 필요하지 않다고 확인되면 나중에 디스크 공간을 절약하기 위해 /var/opt/gitlab/git-data/repositories.old를 제거할 수 있습니다.

  1. 선택적으로 다른 데이터 폴더의 이름을 변경하고 새 폴더를 만듭니다.

    [!warning] 기본 사이트에서 제거됐지만 이 제거가 반영되지 않은 파일이 보조 사이트에 여전히 있을 수 있습니다. 이 단계를 건너뛰면 이러한 파일이 Geo 보조 사이트에서 제거되지 않습니다.

    업로드된 콘텐츠(파일 첨부, 아바타 또는 LFS 오브젝트 등)는 다음 경로 중 하나의 하위 폴더에 저장됩니다:

    • /var/opt/gitlab/gitlab-rails/shared
    • /var/opt/gitlab/gitlab-rails/uploads

    모두 이름을 변경하려면:

    gitlab-ctl stop
    
    mv /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared.old
    mkdir -p /var/opt/gitlab/gitlab-rails/shared
    
    mv /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads.old
    mkdir -p /var/opt/gitlab/gitlab-rails/uploads
    
    gitlab-ctl start postgresql
    gitlab-ctl start geo-postgresql
    

    폴더를 다시 만들고 권한 및 소유권이 올바른지 확인하려면 재구성합니다:

    gitlab-ctl reconfigure
    
  2. 추적 데이터베이스를 재설정합니다.

    [!warning] 선택적 단계 3을 건너뛴 경우 geo-postgresqlpostgresql 서비스가 모두 실행 중인지 확인하세요.

    gitlab-rake db:drop:geo DISABLE_DATABASE_ENVIRONMENT_CHECK=1   # on a secondary app node
    gitlab-ctl reconfigure     # on the tracking database node
    gitlab-rake db:migrate:geo # on a secondary app node
    
  3. 이전에 중지한 서비스를 다시 시작합니다.

    gitlab-ctl start