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 或更高版本。必须能够从注册节点访问它。

按照与您的情况相匹配的说明进行操作:

  • 新安装或首次启用容器镜像仓库表。
  • 将现有容器镜像迁移到元数据数据库:
    • 一步迁移。仅推荐用于相对较小的注册表或无需避免停机的情况。
    • 三步迁移。建议用于较大的容器镜像仓库表。

在您开始之前

  • 启用数据库后,您必须继续使用它。数据库现在是注册表元数据的来源,此时禁用它会导致注册表丢失对数据库活跃时写入的所有镜像的可见性。
  • 在导入步骤完成后,切勿运行离线垃圾收集。该命令与使用元数据数据库的注册表不兼容,并会删除数据。
  • 确认您没有自动化离线垃圾收集。
  • 您可以首先减少注册表的存储以加快进程。
  • 尽可能备份您的容器镜像仓库表数据

新安装

要启用数据库:

  1. 通过添加数据库连接详细信息来编辑 /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'
    }
    
  2. 保存文件并重新配置极狐GitLab
  3. 应用模式迁移
  4. 通过编辑 /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'
    }
    
  5. 保存文件并重新配置极狐GitLab

现有注册表

您可以通过一步或三步迁移现有的容器镜像仓库表数据。几个因素影响迁移的持续时间:

  • 您现有注册表数据的大小。
  • 您的 PostgreSQL 实例的规格。
  • 正在运行的注册表实例的数量。
  • 注册表、PostgreSQL 和您配置的对象存储之间的网络延迟。
note
迁移仅针对带标签的镜像。未标记和未引用的清单及仅由它们引用的层将被遗留并变得不可访问。未标记的镜像从未通过极狐GitLab UI 或 API 可见,但它们可能会在后端变得“悬空”并被遗留。在迁移到新注册表后,所有镜像都将默认进行连续在线垃圾收集,默认情况下删除保留超过 24 小时的未标记和未引用的清单和层。

根据您的注册表安装选择一步或三步方法。

一步迁移

caution
迁移期间必须关闭注册表或保持在“只读”模式。仅在迁移期间无需写入注册表且注册表包含相对少量数据时选择此方法。
  1. 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'
    }
    
  2. 确保注册表设置为“只读”模式。

    编辑您的 /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。
        }
      }
    }
    
  3. 保存文件并重新配置极狐GitLab
  4. 如果尚未完成,应用模式迁移
  5. 运行以下命令:

    sudo gitlab-ctl registry-database import
    
  6. 如果命令成功完成,注册表现在已完全导入。您现在可以启用数据库,关闭配置中的只读模式,并启动注册表服务:

    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
        }
      }
    }
    
  7. 保存文件并重新配置极狐GitLab

您现在可以将元数据数据库用于所有操作!

三步迁移

按照本指南迁移现有的容器镜像仓库表数据。此程序推荐用于较大的数据集或在完成迁移时尝试最小化停机时间。

note
用户报告第一步导入完成的速度为每小时 2 至 4 TB。在较慢的速度下,超过 100TB 数据的注册表可能需要超过 48 小时。

预导入存储库(第一步)

对于较大的实例,此命令可能需要数小时到数天才能完成,具体取决于注册表的大小。在完成第一步时,您可以继续正常使用注册表。

caution
尚无法重启迁移,因此重要的是让迁移运行完成。如果您必须中止操作,则必须重新启动此步骤。
  1. 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'
    }
    
  2. 保存文件并重新配置极狐GitLab
  3. 如果尚未完成,应用模式迁移
  4. 运行第一步以开始迁移:

    sudo gitlab-ctl registry-database import --step-one
    
note
您应该尽快安排以下步骤,以减少所需的停机时间。理想情况下,应在第一步完成后不到一周的时间内进行。步骤一和步骤二之间写入注册表的任何新数据都会导致步骤二需要更多时间。

导入所有存储库数据(第二步)

此步骤需要关闭注册表或将其设置为“只读”模式。为步骤二的执行留出足够的停机时间。

  1. 确保注册表设置为“只读”模式。

    编辑您的 /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。
        }
      }
    }
    
  2. 保存文件并重新配置极狐GitLab
  3. 运行迁移的第二步

    sudo gitlab-ctl registry-database import --step-two
    
  4. 如果命令成功完成,所有镜像现在已完全导入。您现在可以启用数据库,关闭配置中的只读模式,并启动注册表服务:

    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
        }
      }
    }
    
  5. 保存文件并重新配置极狐GitLab

您现在可以将元数据数据库用于所有操作!

导入其余数据(第三步)

即使注册表现在已完全使用数据库作为其元数据,它仍然无法访问任何可能未使用的层 blob。

要完成此过程,请运行迁移的最后一步:

sudo gitlab-ctl registry-database import --step-three

该命令成功退出后,注册表现在已完全迁移到数据库!

迁移后

迁移后大约需要 48 小时才能看到注册表存储减少。这是在线垃圾收集的正常和预期部分,因为此延迟确保在线垃圾收集不会干扰镜像推送。查看监控在线垃圾收集部分,了解如何监控在线垃圾收集器的进度和健康状况。

管理模式迁移

使用以下命令运行容器镜像仓库表元数据数据库的模式迁移。注册表必须启用,并且配置部分必须填写数据库部分。

应用模式迁移

  1. 运行注册表数据库模式迁移

    sudo gitlab-ctl registry-database migrate up
    
  2. 如果注册表正在运行,则必须停止。输入 y 确认并等待进程完成。

note
migrate up 命令提供了一些可用于控制迁移应用方式的额外标志。运行 sudo gitlab-ctl registry-database migrate up --help 以获取详细信息。

撤销模式迁移

如果出现任何问题,您可以撤销模式迁移,但这是一个不可恢复的操作。如果在使用数据库时推送了新镜像,它们将不再可访问。

  1. 撤销注册表数据库模式迁移:

    sudo gitlab-ctl registry-database migrate down
    
note
migrate down 命令提供了一些额外的标志。运行 sudo gitlab-ctl registry-database migrate down --help 以获取详细信息。

在线垃圾收集监控

导入过程后的初始在线垃圾收集运行的持续时间根据导入的镜像数量而异。在此期间,您应监控在线垃圾收集的效率和健康状况。

监控数据库性能

完成导入后,预计数据库会经历一段高负载时期,因为垃圾收集队列会被清空。此高负载是由于在线垃圾收集器处理排队任务时大量单个数据库调用造成的。

定期检查 PostgreSQL 和注册表日志以获取任何错误或警告。在注册表日志中,特别注意按 component=registry.gc.* 过滤的日志。

跟踪指标

使用 Prometheus 和 Grafana 等监控工具来可视化和跟踪垃圾收集指标,重点关注前缀为 registry_gc_* 的指标。这些指标包括标记为删除的对象数量、成功删除的对象、运行间隔和持续时间。请参见启用注册表调试服务器以了解如何启用 Prometheus。

队列监控

通过计算 gc_blob_review_queuegc_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_onlytransaction_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,则必须禁用它:

  1. 编辑您的 postgresql.conf 并设置以下值:

    default_transaction_read_only=off
    
  2. 重启您的 Postgres 服务器以应用这些设置。
  3. 如果适用,请再次尝试应用模式迁移
  4. 重启注册表 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 实例上手动截断表:

  1. 编辑 /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'
    }
    
  2. 使用 PostgreSQL 客户端连接到您的注册表数据库。
  3. 截断 tags 表以删除所有现有条目:

    TRUNCATE TABLE tags RESTART IDENTITY CASCADE;
    
  4. 截断 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。如果您以前有一个正常工作的注册表,这种错误不太可能发生。检查错误日志以获取任何配置错误。