完整性检查 Rake 任务
- Tier: Free, Premium, Ultimate
- Offering: GitLab Self-Managed
GitLab 提供 Rake 任务来检查各种组件的完整性。 另请参阅检查 GitLab 配置的 Rake 任务。
仓库完整性
尽管 Git 非常强大并试图防止数据完整性问题, 但有时还是会出错。以下 Rake 任务旨在 帮助 GitLab 管理员诊断有问题的仓库,以便修复它们。
这些 Rake 任务使用三种不同的方法来确定 Git 仓库的完整性。
- Git 仓库文件系统检查 (
git fsck)。 此步骤验证仓库中对象的连通性和有效性。 - 检查仓库目录中的
config.lock。 - 检查
refs/heads中任何分支/引用的锁定文件。
仅存在 config.lock 或引用锁定
并不一定表示存在问题。当 Git 和 GitLab 对仓库执行操作时,
会定期创建和删除锁定文件。它们的作用是
防止数据完整性问题。但是,如果 Git 操作被中断,这些
锁定可能无法被正确清理。
以下症状可能表明仓库完整性存在问题。如果用户 遇到这些症状,您可以使用下面描述的 Rake 任务来确定 究竟是哪些仓库导致了问题。
- 尝试推送代码时收到错误 -
remote: error: cannot lock ref - 查看 GitLab 仪表板或访问特定项目时出现 500 错误。
检查项目代码仓库
此任务遍历项目代码仓库并运行前面描述的完整性检查。 如果项目使用了池仓库,也会一并检查。 其他类型的 Git 仓库不会被检查。
要检查项目代码仓库:
sudo gitlab-rake gitlab:git:fscksudo -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_projectssudo -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:checksudo -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:secretsbundle 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=1bundle 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 注册令牌可能会损坏。
要重置损坏的令牌:
-
识别具有损坏加密令牌的数据库模型。例如,可以是
Group和Project。 -
识别损坏的令牌。例如
runners_token。 -
要重置损坏的令牌,使用
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_tokensbundle 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! -
如果您确信此操作重置了正确的令牌,请禁用试运行模式并再次运行该操作:
DRY_RUN=false VERBOSE=true MODEL_NAMES=Project,Group TOKEN_NAMES=runners_token gitlab-rake gitlab:doctor:reset_encrypted_tokensbundle 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 文件)的引用:
-
打开 GitLab Rails 控制台。
-
运行以下 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)要更新这些引用以指向本地存储:
-
打开 GitLab Rails 控制台。
-
运行以下 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!要删除这些对缺失本地或远程安全文件的引用:
-
打开 GitLab Rails 控制台。
-
运行以下 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}"