- 已知限制
- 元数据数据库功能支持
- 为 Linux 软件包安装启用元数据数据库
- 管理模式迁移
- 在线垃圾收集监控
- 使用元数据数据库备份
- 降级注册表
- 故障排除
stage: Package
group: Container Registry
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
容器镜像仓库表元数据数据库
DETAILS:
Tier: 基础版, 专业版, 旗舰版
Offering: 私有化部署
- 引入于极狐GitLab 16.4,作为私有化部署实例的 beta 功能。
- 在极狐GitLab 17.3 中 GA。
元数据数据库启用了许多新的注册表功能,包括在线垃圾收集,并提高了许多注册表操作的效率。
默认情况下,容器镜像仓库表使用对象存储来持久化与容器镜像相关的元数据。这种存储元数据的方法限制了数据的访问效率,尤其是跨多个镜像的数据,如列出标签时。通过使用数据库存储这些数据,许多新功能成为可能,包括在线垃圾收集,可以在零停机时间自动移除旧数据。
此数据库与注册表已经使用的对象存储协同工作,但并不替代对象存储。即使迁移到元数据数据库后,您也必须继续维护对象存储解决方案。
对于 Helm Charts 安装,请参见 Helm Charts 文档中的管理容器镜像仓库表元数据数据库。
已知限制
- 不支持在线迁移。
- 尚未确认 Geo 支持。
- 升级版本时必须手动运行注册表数据库迁移。
- 在多节点 Omnibus 极狐GitLab 环境中,无法保证注册表升级期间的零停机。
元数据数据库功能支持
您可以将现有的注册表迁移到元数据数据库,并使用在线垃圾收集。
一些启用了数据库的功能仅对 GitLab.com 启用,并且注册表数据库的自动数据库配置不可用。
为 Linux 软件包安装启用元数据数据库
先决条件:
- 极狐GitLab 17.3 或更高版本。
- PostgreSQL 数据库版本 12 或更高版本。必须能够从注册节点访问它。
按照与您的情况相匹配的说明进行操作:
在您开始之前
- 启用数据库后,您必须继续使用它。数据库现在是注册表元数据的来源,此时禁用它会导致注册表丢失对数据库活跃时写入的所有镜像的可见性。
- 在导入步骤完成后,切勿运行离线垃圾收集。该命令与使用元数据数据库的注册表不兼容,并会删除数据。
- 确认您没有自动化离线垃圾收集。
- 您可以首先减少注册表的存储以加快进程。
- 尽可能备份您的容器镜像仓库表数据。
新安装
要启用数据库:
-
通过添加数据库连接详细信息来编辑
/etc/gitlab/gitlab.rb
,但首先禁用元数据数据库:registry['database'] = { 'enabled' => false, 'host' => 'localhost', 'port' => 5432, 'user' => 'registry-database-user', 'password' => 'registry-database-password', 'dbname' => 'registry-database-name', 'sslmode' => 'require', # 参见 PostgreSQL 文档了解更多信息 https://www.postgresql.org/docs/current/libpq-ssl.html。 'sslcert' => '/path/to/cert.pem', 'sslkey' => '/path/to/private.key', 'sslrootcert' => '/path/to/ca.pem' }
- 保存文件并重新配置极狐GitLab。
- 应用模式迁移。
-
通过编辑
/etc/gitlab/gitlab.rb
并将enabled
设置为true
来启用数据库:registry['database'] = { 'enabled' => true, 'host' => 'localhost', 'port' => 5432, 'user' => 'registry-database-user', 'password' => 'registry-database-password', 'dbname' => 'registry-database-name', 'sslmode' => 'require', # 参见 PostgreSQL 文档了解更多信息 https://www.postgresql.org/docs/current/libpq-ssl.html。 'sslcert' => '/path/to/cert.pem', 'sslkey' => '/path/to/private.key', 'sslrootcert' => '/path/to/ca.pem' }
- 保存文件并重新配置极狐GitLab。
现有注册表
您可以通过一步或三步迁移现有的容器镜像仓库表数据。几个因素影响迁移的持续时间:
- 您现有注册表数据的大小。
- 您的 PostgreSQL 实例的规格。
- 正在运行的注册表实例的数量。
- 注册表、PostgreSQL 和您配置的对象存储之间的网络延迟。
迁移仅针对带标签的镜像。未标记和未引用的清单及仅由它们引用的层将被遗留并变得不可访问。未标记的镜像从未通过极狐GitLab UI 或 API 可见,但它们可能会在后端变得“悬空”并被遗留。在迁移到新注册表后,所有镜像都将默认进行连续在线垃圾收集,默认情况下删除保留超过 24 小时的未标记和未引用的清单和层。
根据您的注册表安装选择一步或三步方法。
一步迁移
迁移期间必须关闭注册表或保持在“只读”模式。仅在迁移期间无需写入注册表且注册表包含相对少量数据时选择此方法。
-
将
database
部分添加到您的/etc/gitlab/gitlab.rb
文件中,但首先禁用元数据数据库:registry['database'] = { 'enabled' => false, # 必须为 false! 'host' => 'localhost', 'port' => 5432, 'user' => 'registry-database-user', 'password' => 'registry-database-password', 'dbname' => 'registry-database-name' 'sslmode' => 'require', # 参见 PostgreSQL 文档了解更多信息 https://www.postgresql.org/docs/current/libpq-ssl.html。 'sslcert' => '/path/to/cert.pem', 'sslkey' => '/path/to/private.key', 'sslrootcert' => '/path/to/ca.pem' }
-
确保注册表设置为“只读”模式。
编辑您的
/etc/gitlab/gitlab.rb
并将maintenance
部分添加到registry['storage']
配置中。例如,对于使用gs://my-company-container-registry
存储桶的gcs
支持的注册表,配置可能为:## 对象存储 - 容器镜像仓库表 registry['storage'] = { 'gcs' => { 'bucket' => "my-company-container-registry", 'chunksize' => 5242880 }, 'maintenance' => { 'readonly' => { 'enabled' => true # 必须设置为 true。 } } }
- 保存文件并重新配置极狐GitLab。
- 如果尚未完成,应用模式迁移。
-
运行以下命令:
sudo gitlab-ctl registry-database import
-
如果命令成功完成,注册表现在已完全导入。您现在可以启用数据库,关闭配置中的只读模式,并启动注册表服务:
registry['database'] = { 'enabled' => true, # 现在必须启用! 'host' => 'localhost', 'port' => 5432, 'user' => 'registry-database-user', 'password' => 'registry-database-password', 'dbname' => 'registry-database-name', 'sslmode' => 'require', # 参见 PostgreSQL 文档了解更多信息 https://www.postgresql.org/docs/current/libpq-ssl.html。 'sslcert' => '/path/to/cert.pem', 'sslkey' => '/path/to/private.key', 'sslrootcert' => '/path/to/ca.pem' } ## 对象存储 - 容器镜像仓库表 registry['storage'] = { 'gcs' => { 'bucket' => "my-company-container-registry", 'chunksize' => 5242880 }, 'maintenance' => { 'readonly' => { 'enabled' => false } } }
- 保存文件并重新配置极狐GitLab。
您现在可以将元数据数据库用于所有操作!
三步迁移
按照本指南迁移现有的容器镜像仓库表数据。此程序推荐用于较大的数据集或在完成迁移时尝试最小化停机时间。
用户报告第一步导入完成的速度为每小时 2 至 4 TB。在较慢的速度下,超过 100TB 数据的注册表可能需要超过 48 小时。
预导入存储库(第一步)
对于较大的实例,此命令可能需要数小时到数天才能完成,具体取决于注册表的大小。在完成第一步时,您可以继续正常使用注册表。
尚无法重启迁移,因此重要的是让迁移运行完成。如果您必须中止操作,则必须重新启动此步骤。
-
将
database
部分添加到您的/etc/gitlab/gitlab.rb
文件中,但首先禁用元数据数据库:registry['database'] = { 'enabled' => false, # 必须为 false! 'host' => 'localhost', 'port' => 5432, 'user' => 'registry-database-user', 'password' => 'registry-database-password', 'dbname' => 'registry-database-name' 'sslmode' => 'require', # 参见 PostgreSQL 文档了解更多信息 https://www.postgresql.org/docs/current/libpq-ssl.html。 'sslcert' => '/path/to/cert.pem', 'sslkey' => '/path/to/private.key', 'sslrootcert' => '/path/to/ca.pem' }
- 保存文件并重新配置极狐GitLab。
- 如果尚未完成,应用模式迁移。
-
运行第一步以开始迁移:
sudo gitlab-ctl registry-database import --step-one
您应该尽快安排以下步骤,以减少所需的停机时间。理想情况下,应在第一步完成后不到一周的时间内进行。步骤一和步骤二之间写入注册表的任何新数据都会导致步骤二需要更多时间。
导入所有存储库数据(第二步)
此步骤需要关闭注册表或将其设置为“只读”模式。为步骤二的执行留出足够的停机时间。
-
确保注册表设置为“只读”模式。
编辑您的
/etc/gitlab/gitlab.rb
并将maintenance
部分添加到registry['storage']
配置中。例如,对于使用gs://my-company-container-registry
存储桶的gcs
支持的注册表,配置可能为:## 对象存储 - 容器镜像仓库表 registry['storage'] = { 'gcs' => { 'bucket' => "my-company-container-registry", 'chunksize' => 5242880 }, 'maintenance' => { 'readonly' => { 'enabled' => true # 必须设置为 true。 } } }
- 保存文件并重新配置极狐GitLab。
-
运行迁移的第二步
sudo gitlab-ctl registry-database import --step-two
-
如果命令成功完成,所有镜像现在已完全导入。您现在可以启用数据库,关闭配置中的只读模式,并启动注册表服务:
registry['database'] = { 'enabled' => true, # 必须设置为 true! 'host' => 'localhost', 'port' => 5432, 'user' => 'registry-database-user', 'password' => 'registry-database-password', 'dbname' => 'registry-database-name', 'sslmode' => 'require', # 参见 PostgreSQL 文档了解更多信息 https://www.postgresql.org/docs/current/libpq-ssl.html。 'sslcert' => '/path/to/cert.pem', 'sslkey' => '/path/to/private.key', 'sslrootcert' => '/path/to/ca.pem' } ## 对象存储 - 容器镜像仓库表 registry['storage'] = { 'gcs' => { 'bucket' => "my-company-container-registry", 'chunksize' => 5242880 }, 'maintenance' => { # 该部分可以移除。 'readonly' => { 'enabled' => false } } }
- 保存文件并重新配置极狐GitLab。
您现在可以将元数据数据库用于所有操作!
导入其余数据(第三步)
即使注册表现在已完全使用数据库作为其元数据,它仍然无法访问任何可能未使用的层 blob。
要完成此过程,请运行迁移的最后一步:
sudo gitlab-ctl registry-database import --step-three
该命令成功退出后,注册表现在已完全迁移到数据库!
迁移后
迁移后大约需要 48 小时才能看到注册表存储减少。这是在线垃圾收集的正常和预期部分,因为此延迟确保在线垃圾收集不会干扰镜像推送。查看监控在线垃圾收集部分,了解如何监控在线垃圾收集器的进度和健康状况。
管理模式迁移
使用以下命令运行容器镜像仓库表元数据数据库的模式迁移。注册表必须启用,并且配置部分必须填写数据库部分。
应用模式迁移
-
运行注册表数据库模式迁移
sudo gitlab-ctl registry-database migrate up
-
如果注册表正在运行,则必须停止。输入
y
确认并等待进程完成。
migrate up
命令提供了一些可用于控制迁移应用方式的额外标志。运行 sudo gitlab-ctl registry-database migrate up --help
以获取详细信息。撤销模式迁移
如果出现任何问题,您可以撤销模式迁移,但这是一个不可恢复的操作。如果在使用数据库时推送了新镜像,它们将不再可访问。
-
撤销注册表数据库模式迁移:
sudo gitlab-ctl registry-database migrate down
migrate down
命令提供了一些额外的标志。运行 sudo gitlab-ctl registry-database migrate down --help
以获取详细信息。在线垃圾收集监控
导入过程后的初始在线垃圾收集运行的持续时间根据导入的镜像数量而异。在此期间,您应监控在线垃圾收集的效率和健康状况。
监控数据库性能
完成导入后,预计数据库会经历一段高负载时期,因为垃圾收集队列会被清空。此高负载是由于在线垃圾收集器处理排队任务时大量单个数据库调用造成的。
定期检查 PostgreSQL 和注册表日志以获取任何错误或警告。在注册表日志中,特别注意按 component=registry.gc.*
过滤的日志。
跟踪指标
使用 Prometheus 和 Grafana 等监控工具来可视化和跟踪垃圾收集指标,重点关注前缀为 registry_gc_*
的指标。这些指标包括标记为删除的对象数量、成功删除的对象、运行间隔和持续时间。请参见启用注册表调试服务器以了解如何启用 Prometheus。
队列监控
通过计算 gc_blob_review_queue
和 gc_manifest_review_queue
表中的行数来检查队列的大小。最初预计会有大队列,行数与导入的 blobs 和清单的数量成比例。队列应该随着时间的推移而减少,这表明垃圾收集正在成功地审查任务。
SELECT COUNT(*) FROM gc_blob_review_queue;
SELECT COUNT(*) FROM gc_manifest_review_queue;
队列大小解释:
- 队列缩小:表明垃圾收集正在成功处理任务。
- 接近零的
gc_manifest_review_queue
:大多数标记为潜在删除的镜像已被审查并被分类为仍在使用或已移除。 -
逾期任务:通过运行以下查询检查逾期 GC 任务:
SELECT COUNT(*) FROM gc_blob_review_queue WHERE review_after < NOW(); SELECT COUNT(*) FROM gc_manifest_review_queue WHERE review_after < NOW();
大量逾期任务表明存在问题。只要队列大小随着时间的推移而减少且逾期任务的数量接近零,大量队列大小并不令人担忧。大量逾期任务应促使紧急检查日志。
检查 GC 日志中是否有指示 blobs 仍在使用的消息,例如 msg=the blob is not dangling
,这意味着它们不会被删除。
调整 blobs 间隔
如果 gc_blob_review_queue
的大小很大,并且您希望增加垃圾收集 blob 或清单工作运行之间的频率,请将间隔配置从默认值(5s
)更新为 1s
:
registry['gc'] = {
'blobs' => {
'interval' => '1s'
},
'manifests' => {
'interval' => '1s'
}
}
在迁移负载清除后,您应微调这些设置以长期避免对数据库和注册表实例的不必要的 CPU 负载。您可以逐渐增加间隔,以达到性能和资源使用之间的平衡。
验证数据一致性
要确保导入后的数据一致性,请使用 crane validate
工具。此工具检查容器镜像仓库表中的所有镜像层和清单是否可访问并正确链接。通过运行 crane validate
,您可以确认注册表中的镜像是完整且可访问的,从而确保成功导入。
审查清理策略
如果您的大多数镜像都已标记,垃圾收集不会显著减少存储空间,因为它仅删除未标记的镜像。
实施清理策略以移除不需要的标签,这最终会导致镜像通过垃圾收集被移除并恢复存储空间。
使用元数据数据库备份
启用元数据数据库后,备份必须像以前一样捕获注册表使用的对象存储,还必须捕获数据库。对象存储和数据库的备份应协调进行,以尽可能接近地捕获注册表的状态。要恢复注册表,您必须同时应用这两个备份。
降级注册表
要在迁移完成后将注册表降级到以前的版本,您必须恢复到所需版本的备份以进行降级。
故障排除
错误:there are pending database migrations
如果注册表已更新并且有待处理的模式迁移,注册表启动失败并显示以下错误消息:
FATA[0000] configuring application: there are pending database migrations, use the 'registry database migrate' CLI command to check and apply them
要解决此问题,请按照步骤应用模式迁移。
错误:offline garbage collection is no longer possible
如果注册表使用元数据数据库并且您尝试运行离线垃圾收集,注册表将失败并显示以下错误消息:
ERRO[0000] this filesystem is managed by the metadata database, and offline garbage collection is no longer possible, if you are not using the database anymore, remove the file at the lock_path in this log message lock_path=/docker/registry/lockfiles/database-in-use
您必须:
- 停止使用离线垃圾收集。
- 如果您不再使用元数据数据库,请删除错误消息中显示的
lock_path
处的锁文件。例如,移除/docker/registry/lockfiles/database-in-use
文件。
错误:cannot execute <STATEMENT> in a read-only transaction
注册表可能无法应用模式迁移,并显示以下错误消息:
err="ERROR: cannot execute CREATE TABLE in a read-only transaction (SQLSTATE 25006)"
此外,如果您尝试运行在线垃圾收集,注册表可能会失败并显示以下错误消息:
error="processing task: fetching next GC blob task: scanning GC blob task: ERROR: cannot execute SELECT FOR UPDATE in a read-only transaction (SQLSTATE 25006)"
您必须通过检查 PostgreSQL 控制台中的 default_transaction_read_only
和 transaction_read_only
的值来验证只读事务是否被禁用。例如:
# SHOW default_transaction_read_only;
default_transaction_read_only
-------------------------------
on
(1 row)
# SHOW transaction_read_only;
transaction_read_only
-----------------------
on
(1 row)
如果这些值中的任何一个设置为 on
,则必须禁用它:
-
编辑您的
postgresql.conf
并设置以下值:default_transaction_read_only=off
- 重启您的 Postgres 服务器以应用这些设置。
- 如果适用,请再次尝试应用模式迁移。
- 重启注册表
sudo gitlab-ctl restart registry
。
错误:cannot import all repositories while the tags table has entries
如果您尝试迁移现有注册表并遇到以下错误:
ERRO[0000] cannot import all repositories while the tags table has entries, you must truncate the table manually before retrying,
see https://gitlab.cn/docs/ee/administration/packages/container_registry_metadata_database.html#troubleshooting
common_blobs=true dry_run=false error="tags table is not empty"
此错误发生在注册表数据库的 tags
表中存在现有条目时,可能发生在您:
要解决此问题,您必须删除 tags
表中的现有条目。您必须在 PostgreSQL 实例上手动截断表:
-
编辑
/etc/gitlab/gitlab.rb
并确保元数据数据库已禁用:registry['database'] = { 'enabled' => false, 'host' => 'localhost', 'port' => 5432, 'user' => 'registry-database-user', 'password' => 'registry-database-password', 'dbname' => 'registry-database-name', 'sslmode' => 'require', # 参见 PostgreSQL 文档了解更多信息 https://www.postgresql.org/docs/current/libpq-ssl.html。 'sslcert' => '/path/to/cert.pem', 'sslkey' => '/path/to/private.key', 'sslrootcert' => '/path/to/ca.pem' }
- 使用 PostgreSQL 客户端连接到您的注册表数据库。
-
截断
tags
表以删除所有现有条目:TRUNCATE TABLE tags RESTART IDENTITY CASCADE;
- 截断
tags
表后,请尝试再次运行迁移过程。
错误:database-in-use lockfile exists
如果您尝试迁移现有注册表并遇到以下错误:
| [0s] step two: import tags failed to import metadata: importing all repositories: 1 error occurred:
* could not restore lockfiles: database-in-use lockfile exists
此错误意味着您之前已经导入了注册表并完成了导入所有存储库数据(步骤二),并且 database-in-use
存在于注册表文件系统中。如果遇到此问题,则不应再次运行导入器。
如果您必须继续,则必须从文件系统中手动删除 database-in-use
锁文件。该文件位于 /path/to/rootdirectory/docker/registry/lockfiles/database-in-use
。
注册表由于元数据管理问题无法启动
注册表可能会因以下错误之一而无法启动:
错误:registry filesystem metadata in use, please import data before enabling the database
此错误发生在您的配置 registry['database'] = { 'enabled' => true}
中启用了数据库,但尚未将现有数据迁移到元数据数据库。
错误:registry metadata database in use, please enable the database
此错误发生在您已完成将现有数据迁移到元数据数据库,但尚未在配置中启用数据库。
检查或创建锁文件的问题
如果遇到以下任何错误:
could not check if filesystem metadata is locked
could not check if database metadata is locked
failed to mark filesystem for database only usage
failed to mark filesystem only usage
注册表无法访问配置的 rootdirectory
。如果您以前有一个正常工作的注册表,这种错误不太可能发生。检查错误日志以获取任何配置错误。