무결성 확인 Rake 작업

Tier: Free, Premium, Ultimate Offering: Self-Managed

GitLab은 여러 컴포넌트의 무결성을 확인하기 위한 Rake 작업을 제공합니다. 또한 GitLab 구성 무결성 Rake 작업을 확인할 수 있습니다.

리포지터리 무결성

Git은 매우 강력하고 데이터 무결성 문제를 방지하려고 노력하지만 때로는 문제가 발생합니다. 다음 Rake 작업은 GitLab 관리자가 문제가있는 리포지터리를 진단하여 수정할 수 있도록 돕고자 합니다.

이러한 Rake 작업은 Git 리포지터리의 무결성을 결정하기 위해 세 가지 다른 방법을 사용합니다.

  1. Git 리포지터리 파일 시스템 확인 (git fsck). 이 단계에서는 리포지터리의 객체의 연결성과 유효성을 확인합니다.
  2. 리포지터리 디렉터리의 config.lock을 확인합니다.
  3. refs/heads의 브랜치/참조 잠금 파일을 확인합니다.

config.lock 또는 참조 잠금 파일의 존재만으로는 문제가 있는 것은 아닙니다. 잠금 파일은 Git 및 GitLab이 리포지터리에서 작업을 수행하는 동안 정기적으로 작성 및 제거됩니다. 이것들은 데이터 무결성 문제를 방지하는 데 도움이 됩니다. 그러나 Git 작업이 중단되면이러한 잠금은 올바르게 정리되지 않을 수 있습니다.

다음 증상이 리포지터리 무결성에 문제가 있음을 나타낼 수 있습니다. 사용자들이 이러한 증상을 겪는 경우 아래 설명된 Rake 작업을 사용하여 정확히 어떤 리포지터리가 문제를 일으키는지 결정할 수 있습니다.

  • 코드를 푸시하려고 할 때 오류가 발생하는 경우 - remote: error: cannot lock ref
  • GitLab 대시 보드를 볼 때 또는 특정 프로젝트에 액세스 할 때 500 오류가 발생하는 경우.

프로젝트 코드 리포지터리 확인

이 작업은 프로젝트 코드 리포지터리를 확인하고 이전에 설명한 무결성 확인 작업을 실행합니다. 프로젝트가 풀 리포지터리를 사용하는 경우에도 확인됩니다. 다른 유형의 Git 리포지터리는 확인되지 않습니다.

  • Linux 패키지 설치:

    sudo gitlab-rake gitlab:git:fsck
    
  • 자체 컴파일 설치:

    sudo -u git -H bundle exec rake gitlab:git:fsck RAILS_ENV=production
    

리포지터리 refs의 체크섬

한 Git 리포지터리는 다른 Git 리포지터리와 비교할 수 있습니다. 두 리포지터리가 동일한 refs를 가지고 있고 두 리포지터리 모두 무결성 검사를 통과한다면 두 리포지터리가 동일하다고 확신할 수 있습니다.

예를 들어 이것은 리포지터리의 백업을 원본 리포지터리와 비교하는 데 사용될 수 있습니다.

모든 GitLab 리포지터리 확인

이 작업은 GitLab 서버의 모든 리포지터리를 확인하고 형식은 <프로젝트 ID>,<체크섬>으로 출력합니다.

  • 만약 리포지터리가 존재하지 않는 경우, 프로젝트 ID는 빈 체크섬입니다.
  • 리포지터리가 존재하지만 비어있는 경우, 출력 체크섬은 0000000000000000000000000000000000000000입니다.
  • 존재하지 않는 프로젝트는 건너뜁니다.

  • Linux 패키지 설치:

    sudo gitlab-rake gitlab:git:checksum_projects
    
  • 자체 컴파일 설치:

    sudo -u git -H bundle exec rake gitlab:git:checksum_projects RAILS_ENV=production
    

예를 들어:

  • ID#2의 프로젝트가 존재하지 않으면 건너뜁니다.
  • ID#4의 프로젝트에는 리포지터리가 없으므로 체크섬은 비어 있습니다.
  • ID#5의 프로젝트에는 비어있는 리포지터리가 있으므로 체크섬은 0000000000000000000000000000000000000000입니다.

그럼 결과는 다음과 같습니다:

1,cfa3f06ba235c13df0bb28e079bcea62c5848af2
3,3f3fb58a8106230e3a6c6b48adc2712fb3b6ef87
4,
5,0000000000000000000000000000000000000000
6,6c6b48adc2712fb3b6ef87cfa3f06ba235c13df0

특정 GitLab 리포지터리 확인

환경 변수 CHECKSUM_PROJECT_IDS에 쉼표로 구분된 정수 디렉터리을 설정하여 특정 프로젝트 ID를 checksum 할 수 있습니다.

sudo CHECKSUM_PROJECT_IDS="1,3" gitlab-rake gitlab:git:checksum_projects

업로드 파일 무결성

GitLab 설치에는 사용자가 업로드하는 다양한 유형의 파일이 있습니다. 이 무결성 확인을 통해 누락된 파일을 감지할 수 있습니다. 또한 로컬로 저장된 파일의 경우 업로드시 체크섬이 생성되어 데이터베이스에 저장되며 이러한 확인을 통해 현재 파일과 비교됩니다.

다음 유형의 파일에 대해 무결성 확인이 지원됩니다:

  • CI artifacts
  • LFS objects
  • 프로젝트 수준 보안 파일 (GitLab 16.1.0에서 도입 됨)
  • 사용자 업로드

  • Linux 패키지 설치:

    sudo gitlab-rake gitlab:artifacts:check
    sudo gitlab-rake gitlab:ci_secure_files:check
    sudo gitlab-rake gitlab:lfs:check
    sudo gitlab-rake gitlab:uploads:check
    
  • 자체 컴파일 설치:

    sudo -u git -H bundle exec rake gitlab:artifacts:check RAILS_ENV=production
    sudo -u git -H bundle exec rake gitlab:ci_secure_files:check RAILS_ENV=production
    sudo -u git -H bundle exec rake gitlab:lfs:check RAILS_ENV=production
    sudo -u git -H bundle exec rake gitlab:uploads:check RAILS_ENV=production
    

이러한 작업은 일부 환경 변수를 허용하며 일부 값을 재정의하는 데 사용할 수 있습니다.

변수 유형 설명
BATCH integer 일괄 처리의 크기를 지정합니다. 기본값은 200입니다.
ID_FROM integer 작업을 시작할 ID를 지정합니다. 값이 포함됩니다.
ID_TO integer 종료할 ID 값을 지정합니다. 값이 포함됩니다.
VERBOSE boolean 실패 사항을 개별적으로 나열하도록 지정합니다.
sudo gitlab-rake gitlab:artifacts:check BATCH=100 ID_FROM=50 ID_TO=250
sudo gitlab-rake gitlab:ci_secure_files:check BATCH=100 ID_FROM=50 ID_TO=250
sudo gitlab-rake gitlab:lfs:check BATCH=100 ID_FROM=50 ID_TO=250
sudo gitlab-rake gitlab:uploads:check BATCH=100 ID_FROM=50 ID_TO=250

예시 출력:

$ sudo gitlab-rake gitlab:uploads:check
Uploads의 무결성 확인 중
- 1..1350: 실패: 0
- 1351..2743: 실패: 0
- 2745..4349: 실패: 2
- 4357..5762: 실패: 1
- 5764..7140: 실패: 2
- 7142..8651: 실패: 0
- 8653..10134: 실패: 0
- 10135..11773: 실패: 0
- 11777..13315: 실패: 0
완료!

예시 상세 출력:

$ sudo gitlab-rake gitlab:uploads:check VERBOSE=1
Uploads의 무결성 확인 중
- 1..1350: 실패: 0
- 1351..2743: 실패: 0
- 2745..4349: 실패: 2
  - Upload: 3573: #<Errno::ENOENT: No such file or directory @ rb_sysopen - /opt/gitlab/embedded/service/gitlab-rails/public/uploads/user-foo/project-bar/7a77cc52947bfe188adeff42f890bb77/image.png>
  - Upload: 3580: #<Errno::ENOENT: No such file or directory @ rb_sysopen - /opt/gitlab/embedded/service/gitlab-rails/public/uploads/user-foo/project-bar/2840ba1ba3b2ecfa3478a7b161375f8a/pug.png>
- 4357..5762: 실패: 1
  - Upload: 4636: #<Google::Apis::ServerError: Server error>
- 5764..7140: 실패: 2
  - Upload: 5812: #<NoMethodError: undefined method `hashed_storage?' for nil:NilClass>
  - Upload: 5837: #<NoMethodError: undefined method `hashed_storage?' for nil:NilClass>
- 7142..8651: 실패: 0
- 8653..10134: 실패: 0
- 10135..11773: 실패: 0
- 11777..13315: 실패: 0
완료!

LDAP 확인

LDAP 확인 Rake 작업은 바인드 DN과 암호 자격 증명(구성된 경우)을 테스트하고 LDAP 사용자의 샘플을 나열합니다. 이 작업은 또한 gitlab:check 작업의 일부로 실행되지만 독립적으로 실행할 수 있습니다. 자세한 내용은 LDAP Rake Tasks - LDAP Check를 참조하세요.

현재 시크릿을 사용하여 데이터베이스 값이 복호화될 수 있는지 확인

이 작업은 데이터베이스의 모든 가능한 암호화된 값을 검사하여 현재의 시크릿 파일(gitlab-secrets.json)을 사용하여 복호화할 수 있는지 확인합니다.

자동 해결 방법은 아직 구현되지 않았습니다. 복호화할 수 없는 값이 있는 경우 해당 값들을 재설정하는 단계를 따를 수 있습니다. 시크릿 파일이 손실된 경우 시크릿 파일이 손실된 경우 문서를 참조하세요.

이 작업은 데이터베이스의 크기에 따라 매우 오랜 시간이 걸릴 수 있으므로 모든 행을 확인합니다.

  • Linux 패키지 설치:

    sudo gitlab-rake gitlab:doctor:secrets
    
  • Self-compiled 설치:

    bundle exec rake gitlab:doctor:secrets RAILS_ENV=production
    

예시 출력

I, [2020-06-11T17:17:54.951815 #27148]  INFO -- : 데이터베이스의 암호화된 값 확인 중
I, [2020-06-11T17:18:12.677708 #27148]  INFO -- : - ApplicationSetting 오류: 0
I, [2020-06-11T17:18:12.823692 #27148]  INFO -- : - 사용자 오류: 0
[...] 다른 암호화된 데이터를 포함하는 모델 가능성 있음
I, [2020-06-11T17:18:14.938335 #27148]  INFO -- : - 그룹 오류: 1
I, [2020-06-11T17:18:15.559162 #27148]  INFO -- : - Operations::FeatureFlagsClient 오류: 0
I, [2020-06-11T17:18:15.575533 #27148]  INFO -- : - ScimOauthAccessToken 오류: 0
I, [2020-06-11T17:18:15.575678 #27148]  INFO -- : 총: 1개의 행이 영향을 받음
I, [2020-06-11T17:18:15.575711 #27148]  INFO -- : 완료!

자세한 모드

별도로 복호화할 수 없는 행과 열에 대한 더 자세한 정보를 얻으려면 VERBOSE 환경 변수를 전달할 수 있습니다.

  • Linux 패키지 설치:

    sudo gitlab-rake gitlab:doctor:secrets VERBOSE=1
    
  • Self-compiled 설치:

    bundle exec rake gitlab:doctor:secrets RAILS_ENV=production VERBOSE=1
    

자세한 예시 출력

I, [2020-06-11T17:17:54.951815 #27148]  INFO -- : 데이터베이스의 암호화된 값 확인 중
I, [2020-06-11T17:18:12.677708 #27148]  INFO -- : - ApplicationSetting 오류: 0
I, [2020-06-11T17:18:12.823692 #27148]  INFO -- : - 사용자 오류: 0
[...] 다른 암호화된 데이터를 포함하는 모델 가능성 있음
D, [2020-06-11T17:19:53.224344 #27351] DEBUG -- : > 그룹[10].runners_token에 오류 발생: Validation failed: Route can't be blank
I, [2020-06-11T17:19:53.225178 #27351]  INFO -- : - 그룹 오류: 1
D, [2020-06-11T17:19:53.225267 #27351] DEBUG -- :   - 그룹[10]: runners_token
I, [2020-06-11T17:18:15.559162 #27148]  INFO -- : - Operations::FeatureFlagsClient 오류: 0
I, [2020-06-11T17:18:15.575533 #27148]  INFO -- : - ScimOauthAccessToken 오류: 0
I, [2020-06-11T17:18:15.575678 #27148]  INFO -- : 총: 1개의 행이 영향을 받음
I, [2020-06-11T17:18:15.575711 #27148]  INFO -- : 완료!

복원할 수 없는 암호화된 토큰 재설정

caution
이 작업은 위험하며 데이터 손실을 야기할 수 있습니다. 극도의 주의를 기울여 진행하십시오. 이 작업을 수행하기 전에 GitLab 내부에 대한 지식이 있어야 합니다.

일부 경우에는 복원할 수 없는 암호화된 토큰이 문제를 일으킬 수 있습니다. 가장 흔히, 그룹 및 프로젝트에 대한 러너 등록 토큰이 매우 큰 인스턴스에서 손상될 수 있습니다.

손상된 토큰을 재설정하려면:

  1. 손상 난 암호화된 토큰을 가진 데이터베이스 모델을 식별합니다. 예를 들어, GroupProject일 수 있습니다.
  2. 손상된 토큰을 식별합니다. 예를 들어 runners_token일 수 있습니다.
  3. 손상된 토큰을 재설정하려면 VERBOSE=true MODEL_NAMES=Model1,Model2 TOKEN_NAMES=broken_token1,broken_token2와 함께 gitlab:doctor:reset_encrypted_tokens을 실행합니다. 예를 들어:

     VERBOSE=true MODEL_NAMES=Project,Group TOKEN_NAMES=runners_token bundle exec rake gitlab:doctor:reset_encrypted_tokens
    

    이 작업이 시도하려는 모든 동작을 볼 수 있습니다:

     I, [2023-09-26T16:20:23.230942 #88920]  INFO -- : Project, Group에서 runners_token 재설정 중
     I, [2023-09-26T16:20:23.230975 #88920]  INFO -- : 실행 중 DRY RUN 모드, 실제 레코드가 업데이트되지 않습니다.
     D, [2023-09-26T16:20:30.151585 #88920] DEBUG -- : > Project[1].runners_token 수정
     I, [2023-09-26T16:20:30.151617 #88920]  INFO -- : 1/9 Projects 확인됨
     D, [2023-09-26T16:20:30.151873 #88920] DEBUG -- : > Project[3].runners_token 수정
     D, [2023-09-26T16:20:30.152975 #88920] DEBUG -- : > Project[10].runners_token 수정
     I, [2023-09-26T16:20:30.152992 #88920]  INFO -- : 11/29 Projects 확인됨
     I, [2023-09-26T16:20:30.153230 #88920]  INFO -- : 21/29 Projects 확인됨
     I, [2023-09-26T16:20:30.153882 #88920]  INFO -- : 29/29 Projects 확인됨
     D, [2023-09-26T16:20:30.195929 #88920] DEBUG -- : > Group[22].runners_token 수정
     I, [2023-09-26T16:20:30.196125 #88920]  INFO -- : 1/19 Groups 확인됨
     D, [2023-09-26T16:20:30.196192 #88920] DEBUG -- : > Group[25].runners_token 수정
     D, [2023-09-26T16:20:30.197557 #88920] DEBUG -- : > Group[82].runners_token 수정
     I, [2023-09-26T16:20:30.197581 #88920]  INFO -- : 11/19 Groups 확인됨
     I, [2023-09-26T16:20:30.198455 #88920]  INFO -- : 19/19 Groups 확인됨
     I, [2023-09-26T16:20:30.198462 #88920]  INFO -- : 완료!
  4. 이 작업이 올바른 토큰을 재설정하는지 확신한다면, 드라이런 모드를 비활성화하고 작업을 다시 실행합니다:

     DRY_RUN=false VERBOSE=true MODEL_NAMES=Project,Group TOKEN_NAMES=runners_token bundle exec rake gitlab:doctor:reset_encrypted_tokens
    

문제 해결

아래는 문서화된 Rake 작업을 사용하여 발견할 수 있는 문제에 대한 해결책입니다.

매달린 객체

gitlab-rake gitlab:git:fsck 작업을 사용하여 다음과 같은 매달린 객체를 찾을 수 있습니다.

dangling blob a12...
dangling commit b34...
dangling tag c56...
dangling tree d78...

이러한 객체를 삭제하려면 housekeeping을 실행해 보세요.

이슈가 지속되면 Rails 콘솔을 통해 가비지 수집을 트리거하려고 해보세요:

p = Project.find_by_path("project-name")
Repositories::HousekeepingService.new(p, :gc).execute

매달린 객체가 기본으로 설정된 2주의 보존 기간보다 새로운 경우 자동으로 만료될 때까지 기다리지 않으려면 다음을 실행하세요:

Repositories::HousekeepingService.new(p, :prune).execute

누락된 원격 업로드에 대한 참조 삭제

gitlab-rake gitlab:uploads:check VERBOSE=1을 사용하여 GitLab 데이터베이스에 여전히 존재하지만 외부에서 삭제된 원격 객체를 감지할 수 있습니다.

에러 메시지가 포함된 예제 출력:

$ sudo gitlab-rake gitlab:uploads:check VERBOSE=1
Uploads의 무결성 확인
- 100..434: 실패: 2
- Upload: 100: 원격 객체가 존재하지 않음
- Upload: 101: 원격 객체가 존재하지 않음
완료!

외부에서 삭제된 원격 업로드에 대한 참조를 삭제하려면 GitLab 레일스 콘솔을 열고 다음을 실행하세요:

uploads_deleted=0
Upload.find_each do |upload|
  next if upload.retrieve_uploader.file.exists?
  uploads_deleted=uploads_deleted + 1
  p upload                            ### 삭제 전 확인
  # p upload.destroy!                 ### 실제 삭제를 원하면 주석 해제
end
p "#{uploads_deleted} 원격 객체가 삭제되었습니다."

누락된 아티팩트에 대한 참조 삭제

gitlab-rake gitlab:artifacts:check VERBOSE=1을 사용하여 GitLab 데이터베이스에 여전히 참조가 있는 아티팩트(또는 job.log 파일)가 외부에서 삭제되었을 때 감지할 수 있습니다.

이 상황이 감지되면 Rake 작업에서 에러 메시지가 표시됩니다. 예를 들면:

작업 아티팩트의 무결성 확인
- 1..15: 실패: 2
  - 작업 아티팩트: 9: #<Errno::ENOENT: No such file or directory @ rb_sysopen - /var/opt/gitlab/gitlab-rails/shared/artifacts/4b/22/4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a/2022_06_30/8/9/job.log>
  - 작업 아티팩트: 15: 원격 객체가 존재하지 않음
완료!

누락된 로컬 및/또는 원격 아티팩트(job.log 파일)에 대한 이러한 참조를 삭제하려면 다음을 실행하세요:

  1. GitLab 레일스 콘솔을 엽니다.
  2. 아래의 루비 코드를 실행하세요:

    artifacts_deleted = 0
    ::Ci::JobArtifact.find_each do |artifact|                      ### 아티팩트 반복
    #  next if artifact.file.filename != "job.log"                 ### `job.log` 파일 참조만 처리하려면 주석 해제
      next if artifact.file.file.exists?                           ### 파일 참조가 유효한 경우 건너뜁니다
      artifacts_deleted += 1
      puts "#{artifact.id}  #{artifact.file.path} is missing."     ### 삭제 전 확인
    #  artifact.destroy!                                           ### 실제 삭제를 원하면 주석 해제
    end
    puts "식별/삭제된 무효 참조 수: #{artifacts_deleted}"
    

LFS 객체에 대한 참조 삭제

만약 gitlab-rake gitlab:lfs:check VERBOSE=1이 데이터베이스에 존재하지만 디스크에 없는 LFS 객체를 감지하면, LFS 문서의 절차를 따라 데이터베이스 항목을 제거하세요.

매달린 객체 리포지터리 참조 업데이트

만약 객체 리포지터리에서 로컬 리포지터리로 이주하고 파일이 누락된 경우 매달린 데이터베이스 참조가 남아 있을 수 있습니다.

이는 다음과 같은 오류가 포함된 마이그레이션 로그에 표시됩니다:

W, [2022-11-28T13:14:09.283833 #10025]  WARN -- : Failed to transfer Ci::JobArtifact ID 11 with error: undefined method `body' for nil:NilClass
W, [2022-11-28T13:14:09.296911 #10025]  WARN -- : Failed to transfer Ci::JobArtifact ID 12 with error: undefined method `body' for nil:NilClass

객체 리포지터리를 비활성화한 후 누락된 아티팩트에 대한 참조를 삭제를 시도하면 다음과 같은 오류가 발생합니다:

RuntimeError (Object Storage is not enabled for JobArtifactUploader)

이러한 참조를 로컬 리포지터리를 가리키도록 업데이트하려면 다음을 실행하세요:

  1. GitLab 레일스 콘솔을 엽니다.
  2. 아래의 루비 코드를 실행하세요:

    artifacts_updated = 0
    ::Ci::JobArtifact.find_each do |artifact|                    ### 아티팩트 반복
      next if artifact.file_store != 2                           ### 이미 로컬 리포지터리를 가리키는 경우 건너뜁니다
      artifacts_updated += 1
      # artifact.update(file_store: 1)                           ### 실제 업데이트를 원하면 주석 해제
    end
    puts "업데이트된 file_store 개수: #{artifacts_updated}"
    

누락된 아티팩트에 대한 참조를 삭제하는 스크립트는 이제 올바르게 작동하고 데이터베이스를 정리합니다.

누락된 보안 파일에 대한 참조 삭제

VERBOSE=1 gitlab-rake gitlab:ci_secure_files:check을 사용하여 다음과 같은 누락된 로컬 또는 원격 보안 파일에 대한 참조를 감지할 수 있습니다.