Help us learn about your current experience with the documentation. Take the survey.

完整性检查 Rake 任务

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab 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 仓库不会被检查

要检查项目代码仓库:

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

仓库引用的校验和

可以通过对每个仓库的所有引用进行校验和计算来 比较两个 Git 仓库。如果两个仓库具有相同的引用, 并且两个仓库都通过了完整性检查,那么我们可以确信 两个仓库是相同的。

例如,这可以用来比较仓库的备份与 源仓库。

检查所有 GitLab 仓库

此任务遍历 GitLab 服务器上的所有仓库,并以 <PROJECT ID>,<CHECKSUM> 格式输出校验和。

  • 如果仓库不存在,项目 ID 为空,校验和为空。
  • 如果仓库存在但是空的,输出的校验和为 0000000000000000000000000000000000000000
  • 不存在的项目会被跳过。

要检查所有 GitLab 仓库:

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,该变量包含以逗号分隔的整数列表,例如:

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

上传文件的完整性

用户可以向 GitLab 安装实例上传各种类型的文件。 这些完整性检查可以检测缺失的文件。此外,对于本地 存储的文件,会在上传时生成校验和并存储在数据库中, 这些检查会将它们与当前文件进行验证。

支持对以下类型的文件进行完整性检查:

  • CI 制品
  • LFS 对象
  • 项目级安全文件(在 GitLab 16.1.0 中引入)
  • 用户上传文件

要检查上传文件的完整性:

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
Checking integrity of Uploads
- 1..1350: Failures: 0
- 1351..2743: Failures: 0
- 2745..4349: Failures: 2
- 4357..5762: Failures: 1
- 5764..7140: Failures: 2
- 7142..8651: Failures: 0
- 8653..10134: Failures: 0
- 10135..11773: Failures: 0
- 11777..13315: Failures: 0
Done!

详细输出示例:

$ sudo gitlab-rake gitlab:uploads:check VERBOSE=1
Checking integrity of Uploads
- 1..1350: Failures: 0
- 1351..2743: Failures: 0
- 2745..4349: Failures: 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: Failures: 1
  - Upload: 4636: #<Google::Apis::ServerError: Server error>
- 5764..7140: Failures: 2
  - Upload: 5812: #<NoMethodError: undefined method `hashed_storage?' for nil:NilClass>
  - Upload: 5837: #<NoMethodError: undefined method `hashed_storage?' for nil:NilClass>
- 7142..8651: Failures: 0
- 8653..10134: Failures: 0
- 10135..11773: Failures: 0
- 11777..13315: Failures: 0
Done!

LDAP 检查

LDAP 检查 Rake 任务测试绑定 DN 和密码凭据 (如果已配置)并列出 LDAP 用户示例。此任务也是 gitlab:check 任务的一部分执行,但可以独立运行。 详情请参阅 LDAP Rake 任务 - LDAP 检查

验证可以使用当前密钥解密数据库值

此任务遍历数据库中所有可能的加密值, 验证它们可以使用当前 密钥文件(gitlab-secrets.json)进行解密。

尚未实现自动解析。如果您有无法 解密的值,可以按照步骤重置它们,请参阅我们关于 密钥文件丢失时该怎么办的文档。

这可能需要很长时间,具体取决于您的 数据库大小,因为它会检查所有表中的所有行。

要验证可以使用当前密钥解密数据库值:

sudo gitlab-rake gitlab:doctor:secrets
bundle exec rake gitlab:doctor:secrets RAILS_ENV=production

示例输出

I, [2020-06-11T17:17:54.951815 #27148]  INFO -- : Checking encrypted values in the database
I, [2020-06-11T17:18:12.677708 #27148]  INFO -- : - ApplicationSetting failures: 0
I, [2020-06-11T17:18:12.823692 #27148]  INFO -- : - User failures: 0
[...] other models possibly containing encrypted data
I, [2020-06-11T17:18:14.938335 #27148]  INFO -- : - Group failures: 1
I, [2020-06-11T17:18:15.559162 #27148]  INFO -- : - Operations::FeatureFlagsClient failures: 0
I, [2020-06-11T17:18:15.575533 #27148]  INFO -- : - ScimOauthAccessToken failures: 0
I, [2020-06-11T17:18:15.575678 #27148]  INFO -- : Total: 1 row(s) affected
I, [2020-06-11T17:18:15.575711 #27148]  INFO -- : Done!

详细模式

要获取有关哪些行和列无法解密的 更详细信息,您可以传递 VERBOSE 环境变量。

要验证可以使用当前密钥解密数据库值并获取详细信息:

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

详细输出示例

I, [2020-06-11T17:17:54.951815 #27148]  INFO -- : Checking encrypted values in the database
I, [2020-06-11T17:18:12.677708 #27148]  INFO -- : - ApplicationSetting failures: 0
I, [2020-06-11T17:18:12.823692 #27148]  INFO -- : - User failures: 0
[...] other models possibly containing encrypted data
D, [2020-06-11T17:19:53.224344 #27351] DEBUG -- : > Something went wrong for Group[10].runners_token: Validation failed: Route can't be blank
I, [2020-06-11T17:19:53.225178 #27351]  INFO -- : - Group failures: 1
D, [2020-06-11T17:19:53.225267 #27351] DEBUG -- :   - Group[10]: runners_token
I, [2020-06-11T17:18:15.559162 #27148]  INFO -- : - Operations::FeatureFlagsClient failures: 0
I, [2020-06-11T17:18:15.575533 #27148]  INFO -- : - ScimOauthAccessToken failures: 0
I, [2020-06-11T17:18:15.575678 #27148]  INFO -- : Total: 1 row(s) affected
I, [2020-06-11T17:18:15.575711 #27148]  INFO -- : Done!

当无法恢复加密令牌时重置它们

此操作很危险,可能导致数据丢失。请极其谨慎地操作。 在执行此操作之前,您必须了解 GitLab 的内部机制。

在某些情况下,加密令牌无法再恢复并导致问题。 最常见的是,在非常大的实例上,组和项目的 runner 注册令牌可能会损坏。

要重置损坏的令牌:

  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 gitlab-rake gitlab:doctor:reset_encrypted_tokens
    bundle exec rake gitlab:doctor:reset_encrypted_tokens RAILS_ENV=production VERBOSE=true MODEL_NAMES=Project,Group TOKEN_NAMES=runners_token

    您将看到此任务尝试执行的每个操作:

    I, [2023-09-26T16:20:23.230942 #88920]  INFO -- : Resetting runners_token on Project, Group if they can not be read
    I, [2023-09-26T16:20:23.230975 #88920]  INFO -- : Executing in DRY RUN mode, no records will actually be updated
    D, [2023-09-26T16:20:30.151585 #88920] DEBUG -- : > Fix Project[1].runners_token
    I, [2023-09-26T16:20:30.151617 #88920]  INFO -- : Checked 1/9 Projects
    D, [2023-09-26T16:20:30.151873 #88920] DEBUG -- : > Fix Project[3].runners_token
    D, [2023-09-26T16:20:30.152975 #88920] DEBUG -- : > Fix Project[10].runners_token
    I, [2023-09-26T16:20:30.152992 #88920]  INFO -- : Checked 11/29 Projects
    I, [2023-09-26T16:20:30.153230 #88920]  INFO -- : Checked 21/29 Projects
    I, [2023-09-26T16:20:30.153882 #88920]  INFO -- : Checked 29 Projects
    D, [2023-09-26T16:20:30.195929 #88920] DEBUG -- : > Fix Group[22].runners_token
    I, [2023-09-26T16:20:30.196125 #88920]  INFO -- : Checked 1/19 Groups
    D, [2023-09-26T16:20:30.196192 #88920] DEBUG -- : > Fix Group[25].runners_token
    D, [2023-09-26T16:20:30.197557 #88920] DEBUG -- : > Fix Group[82].runners_token
    I, [2023-09-26T16:20:30.197581 #88920]  INFO -- : Checked 11/19 Groups
    I, [2023-09-26T16:20:30.198455 #88920]  INFO -- : Checked 19 Groups
    I, [2023-09-26T16:20:30.198462 #88920]  INFO -- : Done!
  4. 如果您确信此操作重置了正确的令牌,请禁用试运行模式并再次运行该操作:

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

gitlab:doctor:reset_encrypted_tokens 任务有以下限制:

  • 非令牌属性,例如 ApplicationSetting:ci_jwt_signing_key 不会被重置。
  • 单个模型记录中存在多个无法解密的属性会导致任务 失败,并出现 TypeError: no implicit conversion of nil into String ... block in aes256_gcm_decrypt 错误。

故障排除

以下是您可能使用前面记录的 Rake 任务 发现的问题的解决方案。

悬空对象

gitlab-rake gitlab:git:fsck 任务可以找到悬空对象,例如:

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

要删除它们,请尝试运行维护

如果问题仍然存在,请尝试通过 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
Checking integrity of Uploads
- 100..434: Failures: 2
- Upload: 100: Remote object does not exist
- Upload: 101: Remote object does not exist
Done!

要删除这些对外部已删除的远程上传文件的引用,请打开 GitLab Rails 控制台 并运行:

uploads_deleted=0
Upload.find_each do |upload|
  next if upload.retrieve_uploader.file.exists?
  uploads_deleted=uploads_deleted + 1
  p upload                            ### allow verification before destroy
  # p upload.destroy!                 ### uncomment to actually destroy
end
p "#{uploads_deleted} remote objects were destroyed."

删除对缺失制品的引用

gitlab-rake gitlab:artifacts:check VERBOSE=1 检测制品(或 job.log 文件)何时:

  • 在 GitLab 外部被删除。
  • 引用仍然存在于 GitLab 数据库中。

当检测到此情况时,Rake 任务会显示错误消息。例如:

Checking integrity of Job artifacts
- 1..15: Failures: 2
  - Job artifact: 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>
  - Job artifact: 15: Remote object does not exist
Done!

要删除这些对缺失本地和/或远程制品(job.log 文件)的引用:

  1. 打开 GitLab Rails 控制台

  2. 运行以下 Ruby 代码:

    artifacts_deleted = 0
    ::Ci::JobArtifact.find_each do |artifact|                      ### Iterate artifacts
    #  next if artifact.file.filename != "job.log"                 ### Uncomment if only `job.log` files' references are to be processed
      next if artifact.file.file.exists?                           ### Skip if the file reference is valid
      artifacts_deleted += 1
      puts "#{artifact.id}  #{artifact.file.path} is missing."     ### Allow verification before destroy
    #  artifact.destroy!                                           ### Uncomment to actually destroy
    end
    puts "Count of identified/destroyed invalid references: #{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 Rails 控制台

  2. 运行以下 Ruby 代码:

    artifacts_updated = 0
    ::Ci::JobArtifact.find_each do |artifact|                    ### Iterate artifacts
      next if artifact.file_store != 2                           ### Skip if file_store already points to local storage
      artifacts_updated += 1
      # artifact.update(file_store: 1)                           ### Uncomment to actually update
    end
    puts "Updated file_store count: #{artifacts_updated}"

删除对缺失制品的引用的脚本现在可以正常运行并清理数据库。

删除对缺失安全文件的引用

VERBOSE=1 gitlab-rake gitlab:ci_secure_files:check 检测安全文件何时:

  • 在 GitLab 外部被删除。
  • 引用仍然存在于 GitLab 数据库中。

当检测到此情况时,Rake 任务会显示错误消息。例如:

Checking integrity of CI Secure Files
- 1..15: Failures: 2
  - Job SecureFile: 9: #<Errno::ENOENT: No such file or directory @ rb_sysopen - /var/opt/gitlab/gitlab-rails/shared/ci_secure_files/4b/22/4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a/2022_06_30/8/9/distribution.cer>
  - Job SecureFile: 15: Remote object does not exist
Done!

要删除这些对缺失本地或远程安全文件的引用:

  1. 打开 GitLab Rails 控制台

  2. 运行以下 Ruby 代码:

    secure_files_deleted = 0
    ::Ci::SecureFile.find_each do |secure_file|                    ### Iterate secure files
      next if secure_file.file.file.exists?                        ### Skip if the file reference is valid
      secure_files_deleted += 1
      puts "#{secure_file.id}  #{secure_file.file.path} is missing."     ### Allow verification before destroy
    #  secure_file.destroy!                                           ### Uncomment to actually destroy
    end
    puts "Count of identified/destroyed invalid references: #{secure_files_deleted}"