GitLab 容器注册表管理
- 层级:Free、Premium、Ultimate
- 提供方式:GitLab 自托管
下一代容器注册表 现已在 GitLab 自托管实例上可供升级。 此升级后的注册表支持在线垃圾回收,并在性能和可靠性方面有显著改进。
通过 GitLab 容器注册表,每个项目都可以拥有自己的空间来存储 Docker 镜像。
有关 Distribution Registry 的更多详细信息:
本文档是管理员指南。若需了解如何使用 GitLab 容器注册表,请参阅用户文档。
启用容器注册表
启用容器注册表的过程取决于您使用的安装类型。
Linux 包安装
如果您通过 Linux 包安装了 GitLab,则容器注册表可能默认可用或不可用。
如果您使用了内置的 Let’s Encrypt 集成,容器注册表会自动启用,并在您的 GitLab 域名(端口 5050)上可用。
否则,容器注册表未启用。要启用它:
容器注册表默认使用 HTTPS 工作。您可以使用 HTTP,但不推荐,且超出本文档范围。
Helm Charts 安装
对于 Helm Charts 安装,请参阅 Helm Charts 文档中的 使用容器注册表。
自编译安装
如果您自行编译 GitLab 安装:
- 您必须使用与所安装 GitLab 版本对应的镜像部署注册表
(例如:
registry.gitlab.com/gitlab-org/build/cng/gitlab-container-registry:v3.15.0-gitlab) - 安装完成后,要启用它,您必须在
gitlab.yml中配置注册表的设置。 - 使用位于
lib/support/nginx/registry-ssl下的示例 NGINX 配置文件,并编辑其以匹配host、port和 TLS 证书路径。
gitlab.yml 的内容如下:
registry:
enabled: true
host: <registry.gitlab.example.com>
port: <5005>
api_url: <http://localhost:5000/>
key: <config/registry.key>
path: <shared/registry>
issuer: <gitlab-issuer>其中:
| 参数 | 说明 |
|---|---|
enabled |
true 或 false。在 GitLab 中启用注册表。默认为 false。 |
host |
注册表运行的主机 URL,用户可在此处访问。 |
port |
外部注册表域监听的端口。 |
api_url |
注册表暴露的内部 API URL。默认为 http://localhost:5000。除非您正在设置外部 Docker 注册表,否则不要更改此值。 |
key |
与注册表 rootcertbundle 配对的私钥位置。 |
path |
此路径应与注册表 rootdirectory 指定的目录相同。该路径需要可被 GitLab 用户、Web 服务器用户和注册表用户读取。 |
issuer |
此值应与注册表中配置的 issuer 相同。 |
如果从源码安装 GitLab,GitLab 不会附带注册表初始化文件。因此,当您修改其设置时,重启 GitLab 并不会重启注册表。请查阅上游文档了解如何实现这一点。
至少要确保您的注册表配置中包含 container_registry 作为服务,并将 https://gitlab.example.com/jwt/auth 作为领域:
auth:
token:
realm: <https://gitlab.example.com/jwt/auth>
service: container_registry
issuer: gitlab-issuer
rootcertbundle: /root/certs/certbundle如果未设置 auth,用户可以在无需身份验证的情况下拉取 Docker 镜像。
容器注册表域名配置
你可以通过以下两种方式配置注册表的外部域名:
- 使用现有的 GitLab 域名。
注册表会监听一个端口,并复用 GitLab 的 TLS 证书。 - 使用完全独立的域名,并为该域名配置新的 TLS 证书。
由于容器注册表需要 TLS 证书,成本可能是一个考虑因素。
在首次配置容器注册表之前,请考虑到这一点。
在现有 GitLab 域名下配置容器注册表
如果容器注册表被配置为使用现有的 GitLab 域名,你可以将容器注册表暴露在一个端口上。这样你就可以复用现有的 GitLab TLS 证书。
如果 GitLab 域名是 https://gitlab.example.com,对外端口是 5050,则配置容器注册表的步骤如下:
- 如果你使用 Linux 包安装,请编辑
gitlab.rb。 - 如果你使用自编译安装,请编辑
gitlab.yml。
确保选择的端口与注册表监听的端口(默认 5000)不同,否则会发生冲突。
主机和容器防火墙规则必须配置为允许流量通过 registry_external_url 行下列出的端口进入,而不是 gitlab_rails['registry_port'](默认 5000)下列出的端口。
-
你的
/etc/gitlab/gitlab.rb应包含注册表 URL 以及现有 GitLab 使用的 TLS 证书和密钥路径:registry_external_url 'https://gitlab.example.com:5050'registry_external_url会在这个现有 GitLab URL 下以 HTTPS 方式监听,但使用不同的端口。如果你的 TLS 证书不在
/etc/gitlab/ssl/gitlab.example.com.crt,且密钥不在/etc/gitlab/ssl/gitlab.example.com.key,请取消注释以下行:registry_nginx['ssl_certificate'] = "/path/to/certificate.pem" registry_nginx['ssl_certificate_key'] = "/path/to/certificate.key" -
保存文件并 重新配置 GitLab,使更改生效。
-
使用以下命令验证:
openssl s_client -showcerts -servername gitlab.example.com -connect gitlab.example.com:5050 > cacert.pem
如果你的证书提供商提供了 CA Bundle 证书,请将其附加到 TLS 证书文件中。
管理员可能希望容器注册表监听任意端口(例如 5678)。然而,注册表和应用服务器位于仅监听端口 80 和 443 的 AWS 应用负载均衡器之后。管理员可以移除 registry_external_url 中的端口号,从而假定使用 HTTP 或 HTTPS。然后,应用将负载均衡器的端口(80 或 443)映射到任意端口的规则。如果用户依赖容器注册表中 docker login 示例,这一点很重要。示例如下:
registry_external_url 'https://registry-gitlab.example.com'
registry_nginx['redirect_http_to_https'] = true
registry_nginx['listen_port'] = 5678-
打开
/home/git/gitlab/config/gitlab.yml,找到registry条目并按以下设置进行配置:registry: enabled: true host: "gitlab.example.com" port: 5050 -
保存文件并 重启 GitLab,使更改生效。
-
同时在 NGINX 中做出相应修改(域名、端口、TLS 证书路径)。
现在用户应该能够使用以下命令,用自己的 GitLab 凭证登录容器注册表:
docker login gitlab.example.com:5050在独立域名下配置容器注册表
当注册表配置为使用自己的域名时,你需要为该特定域名准备一个 TLS 证书(例如 registry.example.com)。如果你的注册表托管在你现有 GitLab 域名的子域名下,你可能需要一个通配符证书。例如,*.gitlab.example.com 是一个通配符,匹配 registry.gitlab.example.com,且与 *.example.com 不同。
除了手动生成的 SSL 证书(此处有说明),Let’s Encrypt 自动生成的证书也受 Linux 包安装的支持。
假设你希望容器注册表可通过 https://registry.gitlab.example.com 访问。
-
将你的 TLS 证书和密钥放在
/etc/gitlab/ssl/<registry.gitlab.example.com>.crt和/etc/gitlab/ssl/<registry.gitlab.example.com>.key中,并确保它们具有正确的权限:chmod 600 /etc/gitlab/ssl/<registry.gitlab.example.com>.* -
TLS 证书就位后,编辑
/etc/gitlab/gitlab.rb文件,添加以下内容:registry_external_url 'https://registry.gitlab.example.com'registry_external_url监听 HTTPS。 -
保存文件并重新配置 GitLab,使更改生效。
如果你有通配符证书,除 URL 外还需指定证书路径,此时 /etc/gitlab/gitlab.rb 应如下所示:
registry_nginx['ssl_certificate'] = "/etc/gitlab/ssl/certificate.pem"
registry_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/certificate.key"-
打开
/home/git/gitlab/config/gitlab.yml,找到registry条目,并用以下设置进行配置:registry: enabled: true host: registry.gitlab.example.com -
保存文件并重启 GitLab,使更改生效。
-
同时在 NGINX 中做相应修改(域名、端口、TLS 证书路径)。
用户现在应能使用其 GitLab 凭证登录容器注册表:
docker login registry.gitlab.example.com全局禁用容器注册表
当你按照以下步骤禁用注册表时,不会删除任何现有的 Docker 镜像。Docker 镜像的移除由注册表应用本身处理。
-
打开
/etc/gitlab/gitlab.rb并将registry['enable']设为false:registry['enable'] = false -
保存文件并重新配置 GitLab,使更改生效。
-
打开
/home/git/gitlab/config/gitlab.yml,找到registry条目并将enabled设为false:registry: enabled: false -
保存文件并重启 GitLab,使更改生效。
全局禁用新项目的容器注册表功能
如果容器注册表已启用,则它应在所有新项目中可用。若要禁用此功能,让项目所有者自行启用容器注册表,请遵循以下步骤。
-
编辑
/etc/gitlab/gitlab.rb并添加以下行:gitlab_rails['gitlab_default_projects_features_container_registry'] = false -
保存文件并重新配置 GitLab,使更改生效。
-
打开
/home/git/gitlab/config/gitlab.yml,找到default_projects_features条目并配置,使container_registry设为false:## 默认项目功能设置 default_projects_features: issues: true merge_requests: true wiki: true snippets: false builds: true container_registry: false -
保存文件并重启 GitLab,使更改生效。
增加令牌时长
在 GitLab 中,容器注册表的令牌每五分钟过期一次。若要增加令牌时长:
- 在左侧边栏底部选择 Admin。
- 选择 Settings > CI/CD。
- 展开 Container Registry。
- 对于 Authorization token duration (minutes),更新数值。
- 选择 Save changes。
配置容器注册表的存储
对于支持的对象存储后端,你可以使用对象版本控制来保存、检索和恢复存储在桶中每个对象的非当前版本。不过,这可能会导致更高的存储用量和成本。由于注册表的工作方式,镜像上传会先存储在临时路径,然后再转移到最终位置。对于对象存储后端(包括S3和GCS),这个转移过程是通过复制后删除实现的。启用对象版本控制后,这些被删除的临时上传工件会被保留为非当前版本,从而增加存储桶的大小。为确保非当前版本在一定时间后被删除,你应该与你的存储提供商一起配置对象生命周期策略。
请勿直接修改容器注册表存储的文件或对象。除注册表写入或删除这些条目外,任何其他操作都可能导致实例范围的数据一致性和稳定性问题,这些问题可能无法恢复。
你可以通过配置存储驱动程序,让容器注册表使用各种存储后端。默认情况下,GitLab容器注册表配置为使用文件系统驱动。
支持的驱动程序如下:
| 驱动程序 | 描述 |
|---|---|
filesystem |
使用本地文件系统上的路径 |
azure |
微软Azure Blob存储 |
gcs |
谷歌云存储 |
s3 |
亚马逊简单存储服务(S3)。请务必将你的存储桶配置为正确的S3权限范围。 |
虽然大多数兼容S3的服务(如MinIO)应该能与容器注册表配合工作,但我们仅保证对AWS S3的支持。由于我们无法验证第三方S3实现是否正确,我们可以调试问题,但如果问题无法在AWS S3桶上重现,我们就无法修补注册表。
使用文件系统
如果你想将镜像存储在文件系统中,你可以更改容器注册表的存储路径,按照以下步骤操作。
该路径可被以下用户访问:
- 运行容器注册表守护进程的用户。
- 运行GitLab的用户。
所有GitLab、Registry和Web服务器用户都必须能访问此目录。
在Linux包安装中,镜像的默认存储位置是/var/opt/gitlab/gitlab-rails/shared/registry。若要更改它:
-
编辑
/etc/gitlab/gitlab.rb:gitlab_rails['registry_path'] = "</path/to/registry/storage>" -
保存文件并重新配置GitLab,使更改生效。
在自行编译安装中,镜像的默认存储位置是/home/git/gitlab/shared/registry。若要更改它:
-
打开
/home/git/gitlab/config/gitlab.yml,找到registry条目并修改path设置:registry: path: shared/registry -
保存文件并重启GitLab,使更改生效。
使用对象存储
如果你想将容器注册表镜像存储在对象存储而非本地文件系统中,你可以配置其中一个受支持的存储驱动程序。
更多信息请参见对象存储。
GitLab不会备份未存储在文件系统中的Docker镜像。如果需要,请启用对象存储提供商的备份功能。
配置用于Linux包安装的对象存储
若要为容器注册表配置对象存储:
- 选择你要使用的存储驱动程序。
- 编辑
/etc/gitlab/gitlab.rb文件并添加适当的配置。 - 保存文件并重新配置GitLab,以使更改生效。
S3存储驱动程序可与Amazon S3或任何与S3兼容的对象存储服务集成。
s3_v2驱动程序(处于Beta阶段)使用AWS SDK v2,仅支持Signature Version 4进行身份验证。该驱动程序提升了性能和可靠性,同时确保与AWS身份验证要求的兼容性,因为对旧签名方法的支持已被弃用。更多信息请参见史诗16272。
有关各驱动程序的完整配置参数列表,请参阅s3_v1和s3_v2。
若要配置S3存储驱动程序,请在你的 /etc/gitlab/gitlab.rb 文件中添加以下配置之一:
# 已弃用:将在GitLab 19.0中移除
registry['storage'] = {
's3' => {
'accesskey' => '<s3-access-key>',
'secretkey' => '<s3-secret-key-for-access-key>',
'bucket' => '<your-s3-bucket>',
'region' => '<your-s3-region>',
'regionendpoint' => '<your-s3-regionendpoint>'
}
}或者
Beta:s3_v2 驱动
registry[‘storage’] = {
‘s3_v2’ => {
‘accesskey’ => ‘
为了提高安全性,你可以通过不包含accesskey和secretkey参数来使用IAM角色代替静态凭证。
为了避免存储成本增加,请在你的S3桶中配置生命周期策略以清除未完成的多部分上传。容器注册表不会自动清理这些内容。对于大多数使用模式来说,未完成多部分上传的三天过期策略效果良好。
当使用MinIO配合s3_v2驱动时,添加checksum_disabled参数以禁用AWS校验和:
registry['storage'] = {
's3_v2' => {
'accesskey' => '<s3-access-key>',
'secretkey' => '<s3-secret-key-for-access-key>',
'bucket' => '<your-s3-bucket>',
'region' => '<your-s3-region>',
'regionendpoint' => '<your-s3-regionendpoint>',
'checksum_disabled' => true
}
}对于S3 VPC端点:
registry['storage'] = {
's3_v2' => { # Beta驱动
'accesskey' => '<s3-access-key>',
'secretkey' => '<s3-secret-key-for-access-key>',
'bucket' => '<your-s3-bucket>',
'region' => '<your-s3-region>',
'regionendpoint' => '<your-s3-vpc-endpoint>',
'pathstyle' => false
}
}S3配置参数:
<your-s3-bucket>: 已有桶的名称。不能包含子目录。regionendpoint: 仅在使用S3兼容服务(如MinIO)或AWS S3 VPC端点时需要。pathstyle: 控制URL格式。设置为true表示host/bucket_name/object(大多数S3兼容服务),或false表示bucket_name.host/object(AWS S3)。
为了避免来自S3 API的503错误,添加maxrequestspersecond参数来设置连接的速率限制:
registry['storage'] = {
's3' => {
'accesskey' => '<s3-access-key>',
'secretkey' => '<s3-secret-key-for-access-key>',
'bucket' => '<your-s3-bucket>',
'region' => '<your-s3-region>',
'regionendpoint' => '<your-s3-regionendpoint>',
'maxrequestspersecond' => 100
}
}Azure存储驱动与Microsoft Azure Blob Storage集成。
有关各驱动完整配置参数列表,请参阅 azure_v1 和 azure_v2。
要配置Azure存储驱动,向你的/etc/gitlab/gitlab.rb文件添加以下配置之一:
# 已弃用:将在GitLab 19.0中移除
registry['storage'] = {
'azure' => {
'accountname' => '<your_storage_account_name>',
'accountkey' => '<base64_encoded_account_key>',
'container' => '<container_name>'
}
}或者
# 测试版:azure_v2 驱动
registry['storage'] = {
'azure_v2' => {
'credentials_type' => '<client_secret>',
'tenant_id' => '<your_tenant_id>',
'client_id' => '<your_client_id>',
'secret' => '<your_secret>',
'container' => '<your_container>',
'accountname' => '<your_account_name>'
}
}默认情况下,Azure 存储驱动使用 core.windows.net 域。你可以在 Azure 部分设置另一个域值(例如,Azure Government Cloud 使用 core.usgovcloudapi.net)。
GCS 存储驱动与 Google 云存储集成。
registry['storage'] = {
'gcs' => {
'bucket' => '<your_bucket_name>',
'keyfile' => '<path/to/keyfile>',
# 如果你的存储桶与其他应用共享(超出注册表范围),请取消以下注释:
# 'rootdirectory' => '/gcs/object/name/prefix'
}
}GitLab 支持所有可用参数。
自行编译安装
存储驱动的配置是在部署 Docker 注册表时创建的注册表配置 YAML 文件中完成的。
s3 存储驱动示例:
storage:
s3:
accesskey: '<s3-access-key>' # 如果使用 IAM 角色,则不需要
secretkey: '<s3-secret-key-for-access-key>' # 如果使用 IAM 角色,则不需要
bucket: '<your-s3-bucket>'
region: '<your-s3-region>'
regionendpoint: '<your-s3-regionendpoint>'
cache:
blobdescriptor: inmemory
delete:
enabled: true<your-s3-bucket> 应该是现有存储桶的名称,且不能包含子目录。
迁移到对象存储而不停机
使用 AWS DataSync 复制注册表数据到或之间的 S3 桶会创建无效的元数据对象。有关详细信息,请参阅 带有空名称的标签。若要在 S3 桶之间移动数据,建议使用 AWS CLI 的 sync 操作。
若要不停止容器注册表来迁移存储,需将容器注册表设置为只读模式。在大实例上,这可能需要容器注册表处于只读模式一段时间。在此期间,你可以从容器注册表中拉取镜像,但无法推送。
-
可选:为减少待迁移的数据量,运行 无停机的垃圾回收工具。
-
此示例使用
awsCLI。如果你之前未配置过 CLI,必须通过运行sudo aws configure来配置凭证。由于非管理员用户可能无法访问容器注册表文件夹,请确保使用sudo。若要检查你的凭证配置,运行ls命令以列出所有桶。sudo aws --endpoint-url <https://your-object-storage-backend.com> s3 ls如果你使用 AWS 作为后端,则不需要
--endpoint-url参数。 -
将初始数据复制到你的 S3 桶,例如使用
awsCLI 的cp或sync命令。确保在桶内将docker文件夹作为顶级文件夹。sudo aws --endpoint-url <https://your-object-storage-backend.com> s3 sync registry s3://mybucket如果你有大量数据,可以通过 运行并行同步操作 来提高性能。
-
执行最终数据同步,将容器注册表置于
read-only模式,并 重新配置 GitLab。 -
同步自初始加载数据以来的任何更改到你的 S3 桶,并删除存在于目标桶但不在源中的文件:
sudo aws --endpoint-url <https://your-object-storage-backend.com> s3 sync registry s3://mybucket --delete --dryrun验证该命令按预期执行后,移除
--dryrun标志并运行命令。--delete标志会删除存在于目标中但不在源中的文件。如果交换源和目标,Registry 中的所有数据将被删除。 -
通过查看以下两个命令返回的文件计数,验证所有容器注册表文件是否已上传到对象存储:
sudo find registry -type f | wc -lsudo aws --endpoint-url <https://your-object-storage-backend.com> s3 ls s3://<mybucket> --recursive | wc -l这些命令的输出结果应匹配,除了
_uploads目录及其子目录中的内容。 -
配置你的注册表以 使用 S3 桶进行存储。
-
若使更改生效,将 Registry 设回
read-write模式并 重新配置 GitLab。
迁移到 Azure 对象存储
registry['storage'] = {
'azure' => {
'accountname' => '<your_storage_account_name>',
'accountkey' => '<base64_encoded_account_key>',
'container' => '<container_name>',
'trimlegacyrootprefix' => true
}
}storage:
azure:
accountname: <your_storage_account_name>
accountkey: <base64_encoded_account_key>
container: <container_name>
trimlegacyrootprefix: true默认情况下,Azure 存储驱动程序使用 core.windows.net 领域。你可以在 azure 部分中为 realm 设置另一个值(例如,对于 Azure 政府云,使用 core.usgovcloudapi.net)。
禁用存储驱动器的重定向
默认情况下,访问配置了远程后端的注册表的用户会被重定向到存储驱动器的默认后端。例如,可以使用 s3 存储驱动器配置注册表,该驱动器会将请求重定向到远程 S3 存储桶,以减轻 GitLab 服务器的负载。
然而,这种行为对通常无法访问公共服务器的内部主机使用的注册表来说是不理想的。要禁用重定向并 代理下载,请按如下方式将 disable 标志设置为 true。这会使所有流量始终通过 Registry 服务。虽然这会提高安全性(由于存储后端不可公开访问,攻击面更小),但性能会更差(所有流量都通过服务重定向)。
-
编辑
/etc/gitlab/gitlab.rb:registry['storage'] = { 's3' => { 'accesskey' => '<s3_access_key>', 'secretkey' => '<s3_secret_key_for_access_key>', 'bucket' => '<your_s3_bucket>', 'region' => '<your_s3_region>', 'regionendpoint' => '<your_s3_regionendpoint>' }, 'redirect' => { 'disable' => true } } -
保存文件并 重新配置 GitLab 以使更改生效。
-
将
redirect标志添加到您的注册表配置 YAML 文件中:storage: s3: accesskey: '<s3_access_key>' secretkey: '<s3_secret_key_for_access_key>' bucket: '<your_s3_bucket>' region: '<your_s3_region>' regionendpoint: '<your_s3_regionendpoint>' redirect: disable: true cache: blobdescriptor: inmemory delete: enabled: true -
保存文件并 重启 GitLab 以使更改生效。
加密的 S3 存储桶
您可以对启用了 SSE-S3 或 SSE-KMS 加密 的 S3 存储桶使用 AWS KMS 进行服务器端加密。客户主密钥(CMK)和 SSE-C 加密不受支持,因为这需要在每个请求中发送加密密钥。
对于 SSE-S3,您必须在注册表设置中启用 encrypt 选项。具体操作取决于您安装 GitLab 的方式。请按照此处与您的安装方法匹配的说明进行操作。
-
编辑
/etc/gitlab/gitlab.rb:registry['storage'] = { 's3' => { 'accesskey' => '<s3_access_key>', 'secretkey' => '<s3_secret_key_for_access_key>', 'bucket' => '<your_s3_bucket>', 'region' => '<your_s3_region>', 'regionendpoint' => '<your_s3_regionendpoint>', 'encrypt' => true } } -
保存文件并 重新配置 GitLab 以使更改生效。
-
编辑您的注册表配置 YAML 文件:
storage: s3: accesskey: '<s3_access_key>' secretkey: '<s3_secret_key_for_access_key>' bucket: '<your_s3_bucket>' region: '<your_s3_region>' regionendpoint: '<your_s3_regionendpoint>' encrypt: true -
保存文件并重启注册表服务器。
存储限制
没有存储限制,这意味着用户可以上传任意大小的无限量 Docker 镜像。此设置将在未来版本中进行配置。
更改注册表的内部端口
Registry 服务器默认在本地主机上的端口 5000 监听,这是 Registry 服务器应接受连接的地址。以下示例中将 Registry 的端口设置为 5010。
-
打开
/etc/gitlab/gitlab.rb并设置registry['registry_http_addr']:registry['registry_http_addr'] = "localhost:5010" -
保存文件并 重新配置 GitLab 以使更改生效。
-
打开 Registry 服务器的配置文件并编辑
http:addr值:http: addr: localhost:5010 -
保存文件并重启 Registry 服务器。
按项目禁用容器注册表
如果你的GitLab实例中启用了容器注册表,但你不需要它用于你的项目,你可以从项目的设置中禁用它。disable it from your project’s settings。
使用外部容器注册表作为GitLab的身份验证端点
在GitLab 15.8中,GitLab中使用第三方容器注册表已被弃用,支持已在GitLab 16.0结束。 如果你需要使用第三方容器注册表而不是GitLab容器注册表,请在反馈问题958中告诉我们你的用例。
如果你使用外部容器注册表,与容器注册表相关的某些功能可能不可用或有固有风险。
为了使集成正常工作,外部注册表必须配置为使用JSON Web令牌向GitLab进行身份验证。外部注册表的运行时配置external registry’s runtime configuration 必须包含以下条目:
auth:
token:
realm: https://<gitlab.example.com>/jwt/auth
service: container_registry
issuer: gitlab-issuer
rootcertbundle: /root/certs/certbundle如果没有这些条目,注册表登录无法通过GitLab进行身份验证。GitLab也无法识别项目层级下的嵌套镜像名称,例如registry.example.com/group/project/image-name:tag 或 registry.example.com/group/project/my/image-name:tag,而只识别registry.example.com/group/project:tag。
Linux包安装
你可以使用GitLab作为身份验证端点与外部容器注册表配合使用。
-
打开
/etc/gitlab/gitlab.rb并设置必要的配置:gitlab_rails['registry_enabled'] = true gitlab_rails['registry_api_url'] = "https://<external_registry_host>:5000" gitlab_rails['registry_issuer'] = "gitlab-issuer"gitlab_rails['registry_enabled'] = true是启用GitLab容器注册表功能和认证端点所需的。即使启用了此选项,GitLab捆绑的容器注册表服务也不会启动。gitlab_rails['registry_api_url'] = "http://<external_registry_host>:5000"必须修改为匹配Registry安装的主机。如果外部注册表配置为使用TLS,还必须指定https。
-
GitLab和外部容器注册表之间需要进行安全通信,因此需要一个证书密钥对。你需要创建一个证书密钥对,将公共证书(
rootcertbundle)配置到外部容器注册表中,并将私钥配置到GitLab中。为此,向/etc/gitlab/gitlab.rb添加以下内容:# registry['internal_key'] 应包含自定义密钥文件的内容。密钥文件中的换行符应使用 '\n' 字符标记 # 示例: registry['internal_key'] = "---BEGIN RSA PRIVATE KEY---\nMIIEpQIBAA\n" # 可选地定义一个自定义文件,用于Linux包安装将 registry['internal_key'] 的内容写入其中。 gitlab_rails['registry_key_path'] = "/custom/path/to/registry-key.key"每次执行重新配置时,
registry_key_path指定的文件会被填充为internal_key指定的内容。如果未指定文件,Linux包安装会默认将其设为/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key并进行填充。 -
若要更改GitLab容器注册表页面中显示的容器注册表URL,请设置以下配置:
gitlab_rails['registry_host'] = "<registry.gitlab.example.com>" gitlab_rails['registry_port'] = "5005" -
保存文件并重新配置GitLab以使更改生效。
自编译安装
-
打开
/home/git/gitlab/config/gitlab.yml,并在registry下编辑配置设置:## 容器注册表 registry: enabled: true host: "<registry.gitlab.example.com>" port: "5005" api_url: "https://<external_registry_host>:5000" path: /var/lib/registry key: </path/to/keyfile> issuer: gitlab-issuer阅读更多了解这些参数的含义。
-
保存文件并重启GitLab以使更改生效。
配置容器注册表通知
您可以配置容器注册表,使其在注册表中发生事件时发送 Webhook 通知。
有关容器注册表通知配置选项的更多信息,请参阅 Docker 注册表通知文档。
对 threshold 参数的支持已在 GitLab 17.0 中被弃用,并计划在 18.0 中移除。请改用 maxretries。
您可以为容器注册表配置多个端点。
若要为 Linux 包安装配置通知端点:
-
编辑
/etc/gitlab/gitlab.rb文件:registry['notifications'] = [ { 'name' => '<test_endpoint>', 'url' => 'https://<gitlab.example.com>/api/v4/container_registry_event/events', 'timeout' => '500ms', 'threshold' => 5, # 已弃用:请改用 `maxretries`。 'maxretries' => 5, 'backoff' => '1s', 'headers' => { "Authorization" => ["<AUTHORIZATION_EXAMPLE_TOKEN>"] } } ] gitlab_rails['registry_notification_secret'] = '<AUTHORIZATION_EXAMPLE_TOKEN>' # 必须与 registry['notifications'] 中的认证令牌匹配
将 <AUTHORIZATION_EXAMPLE_TOKEN> 替换为一个以字母开头的区分大小写的字母数字字符串。你可以通过以下命令生成一个:< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c 32 | sed "s/^[0-9]*//"; echo
- 保存文件并 重新配置 GitLab,使更改生效。
通知端点的配置是在部署 Docker 注册表时创建的注册表配置 YAML 文件中完成的。
示例如下:
notifications:
endpoints:
- name: <alistener>
disabled: false
url: https://<my.listener.com>/event
headers: <http.Header>
timeout: 500
threshold: 5 # 已弃用:请改用 `maxretries`。
maxretries: 5
backoff: 1000运行清理策略
先决条件:
- 如果使用分布式架构,且容器注册表运行在与 Sidekiq 不同的节点上,请遵循 使用外部 Sidekiq 时配置容器注册表 中的步骤。
在您 创建清理策略 后,可以立即运行它来减少容器注册表的存储空间。无需等待计划的清理操作。
为减少给定项目使用的容器注册表磁盘空间,管理员可以执行以下操作:
- 按项目检查磁盘空间使用情况,识别需要清理的项目。
- 使用 GitLab Rails 控制台运行清理策略,删除镜像标签。
- 运行垃圾回收,删除未引用的层和未标记的清单。
按项目查看注册表磁盘空间使用情况
若要查找每个项目的磁盘空间使用情况,请在 GitLab Rails 控制台 中运行以下命令:
projects_and_size = [["project_id", "creator_id", "registry_size_bytes", "project path"]]
# 你需要指定要查询的项目。你可以通过任意方式获取这些项目。
projects = Project.last(100)
registry_metadata_database = ContainerRegistry::GitlabApiClient.supports_gitlab_api?
if registry_metadata_database
projects.each do |project|
size = project.container_repositories_size
if size > 0
projects_and_size << [project.project_id, project.creator&.id, size, project.full_path]
end
end
else
projects.each do |project|
project_layers = {}
project.container_repositories.each do |repository|
repository.tags.each do |tag|
tag.layers.each do |layer|
project_layers[layer.digest] ||= layer.size
end
end
end
total_size = project_layers.values.compact.sum
if total_size > 0
projects_and_size << [project.project_id, project.creator&.id, total_size, project.full_path]
end
end
end以逗号分隔的输出形式打印
projects_and_size.each do |ps| puts “%s,%s,%s,%s” % ps end
该脚本基于容器镜像层计算大小。由于层可能在多个项目间共享,结果近似但能很好地指示项目间的相对磁盘使用情况。
要运行清理策略来移除镜像标签,请在 [GitLab Rails控制台](../operations/rails_console.md) 中运行以下命令:
```ruby
# 要清理其容器注册表的项目数字ID
P = <project_id>
# 拥有该项目Developer、Maintainer或Owner角色的用户的数字ID
U = <user_id>
# 获取所需详细信息/对象
user = User.find_by_id(U)
project = Project.find_by_id(P)
policy = ContainerExpirationPolicy.find_by(project_id: P)
# 遍历每个容器仓库
project.container_repositories.find_each do |repo|
puts repo.attributes
# 启动标签清理
puts Projects::ContainerRepository::CleanupTagsService.new(container_repository: repo, current_user: user, params: policy.attributes.except("created_at", "updated_at")).execute
end您也可以按计划运行清理。
若要在整个实例范围内为所有项目启用清理策略,您需要找到所有已启用容器注册表但未启用清理策略的项目:
# 找到容器注册表已启用且清理策略未启用的所有项目
projects = Project.find_by_sql ("SELECT * FROM projects WHERE id IN (SELECT project_id FROM container_expiration_policies WHERE enabled=false AND id IN (SELECT project_id FROM container_repositories))")
# 遍历每个项目
projects.each do |p|
# 打印项目ID和完整项目名称
puts "#{p.id},#{p.full_name}"
end容器注册表元数据库
- 层级:免费、高级、旗舰
- 提供方式:GitLab自托管
元数据库支持许多新的注册表功能,包括在线垃圾回收,并提高了许多注册表操作的效率。有关详情,请参阅容器注册表元数据库页面。
容器注册表垃圾回收
先决条件:
- 您必须通过Linux包或GitLab Helm图表安装GitLab。
您的对象存储提供商(如Amazon S3生命周期)中的保留策略可能会阻止对象被正确删除。
容器注册表可能占用大量存储空间,您可能希望减少存储使用。在列出的选项中,删除标签是最有效的方式。然而,仅删除标签并不会删除镜像层,只会让底层镜像清单失去标签。
为了更有效地释放空间,容器注册表有一个垃圾收集器,可以删除未引用的层(可选地)以及未标记的清单。
要启动垃圾收集器,请运行以下gitlab-ctl命令:
`registry-garbage-collect`执行垃圾收集所需的时间与容器注册表的数据量成正比。
registry-garbage-collect命令会在垃圾回收前关闭容器注册表,仅在垃圾回收完成后重新启动。如果您希望避免停机时间,可以手动将容器注册表设置为只读模式并绕过gitlab-ctl。
此命令仅当元数据位于对象存储中时才会执行。如果启用了容器注册表元数据库,则不会执行此命令。
理解内容可寻址层
考虑以下示例,您首先构建镜像:
# 这会构建一个包含sha256:<111111...>内容的镜像
docker build -t <my.registry.com>/<my.group>/<my.project>:latest .
docker push <my.registry.com>/<my.group>/<my.project>:latest现在,您用新版本覆盖latest:
# 这会构建一个包含 sha256:<222222...> 内容的镜像
docker build -t <my.registry.com>/<my.group>/<my.project>:latest .
docker push <my.registry.com>/<my.group>/<my.project>:latest现在,latest 标签指向 sha256:<222222…> 的清单。
由于注册表的架构,当拉取镜像 <my.registry.com>/<my.group>/<my.project>@sha256:<111111...> 时,这些数据仍可访问,只是无法再通过 latest 标签直接获取。
移除未引用的层
镜像层是容器注册表存储的核心部分。若某层未被任何镜像清单引用,则视为未引用层——这类层是容器注册表垃圾回收器的默认清理对象。
若未修改配置文件默认位置,执行:
sudo gitlab-ctl registry-garbage-collect若已调整容器注册表 config.yml 路径,执行:
sudo gitlab-ctl registry-garbage-collect /path/to/config.yml也可通过移除未标记清单和未引用层释放额外空间。
移除未标记的清单和未引用的层
默认下,容器注册表垃圾回收器会忽略未标记镜像(用户可通过摘要拉取这类镜像);未来还能对镜像重新打标,使其在 GitLab UI/API 中重现。
若无需保留未标记镜像及其独占层,可全部删除。在 registry-garbage-collect 命令中加 -m 参数:
sudo gitlab-ctl registry-garbage-collect -m若对删除未标记镜像存疑,操作前先备份数据。
无停机执行垃圾回收
要让注册表在线时做垃圾回收,需将其设为只读模式,并绕开内置的 gitlab-ctl registry-garbage-collect 命令。
只读模式下可拉取镜像,但无法推送;且整个回收过程需保持只读。默认的注册表存储路径为 /var/opt/gitlab/gitlab-rails/shared/registry。
启用只读模式的步骤:
- 编辑
/etc/gitlab/gitlab.rb,配置只读模式:registry['storage'] = { 'filesystem' => { 'rootdirectory' => "<your_registry_storage_path>" }, 'maintenance' => { 'readonly' => { 'enabled' => true } } } - 保存后重配 GitLab:
(此步会将注册表切换至只读模式)
sudo gitlab-ctl reconfigure - 触发垃圾回收命令:
(回收耗时与数据量正相关)
# 仅移除未引用层 sudo /opt/gitlab/embedded/bin/registry garbage-collect /var/opt/gitlab/registry/config.yml # 移除未标记清单+未引用层 sudo /opt/gitlab/embedded/bin/registry garbage-collect -m /var/opt/gitlab/registry/config.yml - 回收完成后,将
/etc/gitlab/gitlab.rb改回读写模式:registry['storage'] = { 'filesystem' => { 'rootdirectory' => "<your_registry_storage_path>" }, 'maintenance' => { 'readonly' => { 'enabled' => false } } } - 重配 GitLab 生效:
sudo gitlab-ctl reconfigure
定期执行垃圾回收
建议每周选注册表空闲时段(如凌晨)自动运行回收任务。最简方式是添加 crontab 计划:
在 /etc/cron.d/registry-garbage-collect 创建文件:
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# 每周日 04:05 执行
5 4 * * 0 root gitlab-ctl registry-garbage-collect若需同时清理未标记镜像,可在命令后追加 -m 参数(参考移除未标记清单和未引用层)。
停止垃圾回收
如果您预计会停止垃圾回收,应按照无停机执行垃圾回收中的描述手动运行垃圾回收。之后可以通过按下Control+C来停止垃圾回收。
否则,中断gitlab-ctl可能会使您的注册服务处于关闭状态。在这种情况下,您必须在系统中找到该垃圾回收进程,以便gitlab-ctl命令能够重新启动注册服务。
此外,在过程的标记阶段无法保存进度或结果。只有当 blob 开始被删除时,才会进行永久性操作。
持续零停机垃圾回收
如果迁移到元数据数据库,则可以在后台运行垃圾回收,无需安排时间或要求只读模式。
按组件扩展
本节概述了随着注册表流量增加,各组件可能出现的性能瓶颈。每个小节的建议大致按从小到大注册工作负载的顺序排列。注册表未包含在参考架构中,也没有针对座位数或每秒请求数的扩展指南。
数据库
- 迁移到独立数据库:随着数据库负载的增加,通过将注册表元数据数据库移动到独立的物理数据库来垂直扩展。独立数据库可以增加注册表数据库可用的资源量,同时隔离注册表产生的流量。
- 迁移到高可用 PostgreSQL 第三方解决方案:类似于Praefect,迁移到信誉良好的提供商或解决方案可实现高可用性,适用于多节点注册部署。您必须选择支持原生 Postgres 分区、触发器和函数的提供商,因为注册表大量使用这些功能。
注册表服务器
- 迁移到独立节点:独立节点是一种垂直扩展的方式,可增加容器注册表服务器进程可用的资源。
- 在负载均衡器后运行多个注册表节点:尽管单个大型节点可以处理大量流量,但注册表通常旨在通过多个部署水平扩展。配置多个较小节点还支持自动扩展等技术。
Redis 缓存
启用Redis缓存可以提高性能,但也启用了重命名存储库等功能。
- Redis 服务器:支持单个 Redis 实例,这是访问 Redis 缓存优势的最简单方式。
- Redis Sentinel:也支持 Redis Sentinel,可使缓存实现高可用性。
- Redis Cluster:随着部署规模扩大,也可以使用 Redis Cluster 进行进一步扩展。
存储
- 本地文件系统:默认为本地文件系统,相对高效,但不适合多节点部署或大量注册表数据。
- 对象存储:使用对象存储以实现对更大数量注册表数据的实际存储。对象存储也适用于多节点注册部署。
在线垃圾回收
- 调整默认值:如果在线垃圾回收未能可靠地清理审核队列,您可以调整
gc配置部分的manifests和blobs部分下的interval设置。默认值为5s,也可以用毫秒配置,例如500ms。 - 通过注册表服务器水平扩展:如果您正在通过多节点部署水平扩展注册表应用程序,在线垃圾回收会自动扩展,无需更改配置。
在 Linux 软件包安装中配置 GitLab 和注册表于不同节点
默认情况下,GitLab 包假定两个服务在同一节点上运行。在不同节点上运行它们需要单独配置。
配置选项
应在相应节点的/etc/gitlab/gitlab.rb中设置以下配置选项。
注册节点设置
| 选项 | 描述 |
|---|---|
registry['registry_http_addr'] |
注册表监听的网络地址和端口。必须能被 Web 服务器或负载均衡器访问。默认值:通过程序设置。 |
registry['token_realm'] |
认证端点 URL,通常是 GitLab 实例的 URL。用户必须能够访问它。默认值:通过程序设置。 |
registry['http_secret'] |
用于防止客户端篡改的安全令牌。生成方式为随机字符串。 |
registry['internal_key'] |
令牌签名密钥,在注册服务器上创建但由 GitLab 使用。默认值:自动生成。 |
registry['internal_certificate'] |
令牌签名的证书。默认值:自动生成。 |
registry['rootcertbundle'] |
存储 internal_certificate 的文件路径。默认值:通过程序设置。 |
registry['health_storagedriver_enabled'] |
启用存储驱动器的健康监控。默认值:通过程序设置。 |
gitlab_rails['registry_key_path'] |
存储 internal_key 的文件路径。默认值:通过程序设置。 |
gitlab_rails['registry_issuer'] |
令牌颁发者名称。必须在注册表和 GitLab 配置中匹配。默认值:通过程序设置。 |
容器注册表中使用 Amazon S3 签名版本 2 进行请求认证的支持已在 GitLab 17.8 中弃用,并计划在 18.0 中移除。请改用签名版本 4。这是一个破坏性变更。有关更多信息,请参阅 问题 1449。
GitLab 节点设置
| 选项 | 描述 |
|---|---|
gitlab_rails['registry_enabled'] |
启用 GitLab 注册表 API 集成。必须设置为 true。 |
gitlab_rails['registry_api_url'] |
GitLab 使用的内部注册表 URL(对用户不可见)。使用带有方案的 registry['registry_http_addr']。默认值:通过程序设置。 |
gitlab_rails['registry_host'] |
不带方案的公共注册表主机名(例如:registry.gitlab.example)。此地址显示给用户。 |
gitlab_rails['registry_port'] |
显示给用户的公共注册表端口号。 |
gitlab_rails['registry_issuer'] |
令牌颁发者名称,必须与注册表的配置匹配。 |
gitlab_rails['registry_key_path'] |
注册表使用的证书密钥的文件路径。 |
gitlab_rails['internal_key'] |
GitLab 使用的令牌签名密钥内容。 |
设置节点
要在单独的节点上配置 GitLab 和容器注册表:
-
在注册表节点上,使用以下设置编辑
/etc/gitlab/gitlab.rb:# 注册表服务器详情 # - IP 地址: 10.30.227.194 # - 域名: registry.example.com # 禁用不需要的服务 gitlab_workhorse['enable'] = false puma['enable'] = false sidekiq['enable'] = false postgresql['enable'] = false redis['enable'] = false gitlab_kas['enable'] = false gitaly['enable'] = false nginx['enable'] = false # 配置注册表设置 registry['enable'] = true registry['registry_http_addr'] = '0.0.0.0:5000' registry['token_realm'] = 'https://<gitlab.example.com>' registry['http_secret'] = '<6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b>' # 配置 GitLab Rails 设置 gitlab_rails['registry_issuer'] = 'omnibus-gitlab-issuer' gitlab_rails['registry_key_path'] = '/etc/gitlab/gitlab-registry.key' -
在 GitLab 节点上,使用以下设置编辑
/etc/gitlab/gitlab.rb:# GitLab 服务器详情 # - IP 地址: 10.30.227.149 # - 域名: gitlab.example.com # 配置 GitLab URL external_url 'https://<gitlab.example.com>' # 配置注册表设置 gitlab_rails['registry_enabled'] = true gitlab_rails['registry_api_url'] = '<http://10.30.227.194:5000>' gitlab_rails['registry_host'] = '<registry.example.com>' gitlab_rails['registry_port'] = 5000 gitlab_rails['registry_issuer'] = 'omnibus-gitlab-issuer' gitlab_rails['registry_key_path'] = '/etc/gitlab/gitlab-registry.key' -
同步两个节点之间的
/etc/gitlab/gitlab-secrets.json文件:- 将文件从 GitLab 节点复制到注册表节点。
- 确保文件权限正确。
- 在两个节点上运行
sudo gitlab-ctl reconfigure。
容器注册表架构
用户可以将自己的 Docker 镜像存储在容器注册表中。由于注册表面向客户端,因此它直接暴露在 Web 服务器或负载均衡器(LB)上。
%%{init: { "fontFamily": "GitLab Sans" }}%%
flowchart LR
accTitle: 容器注册表认证流程
accDescr: 展示用户如何通过 GitLab API 与容器注册表进行身份验证以推送和拉取 Docker 镜像
A[用户] --->|1: 通过 443 端口执行 Docker 登录| C{前端负载均衡器}
C --->|2: 无令牌的连接尝试失败| D[容器注册表]
C --->|5: 携带令牌的连接成功| D[容器注册表]
C --->|3: Docker 请求令牌| E[API 前端]
E --->|4: API 返回已签名的令牌| C
linkStyle 1 stroke-width:4px,stroke:red
linkStyle 2 stroke-width:4px,stroke:green
认证流程包括以下步骤:
- 用户在其客户端上运行
docker login registry.gitlab.example。该请求到达端口 443 上的 Web 服务器(或 LB)。 - Web 服务器连接到注册表后端池(默认端口 5000)。由于用户没有有效令牌,注册表返回
401 UnauthorizedHTTP 状态码和一个获取令牌的 URL。该 URL 由注册表配置中的token_realm设置定义,指向 GitLab API。 - Docker 客户端连接到 GitLab API 并获取令牌。
- API 使用注册表密钥对令牌进行签名并发送给 Docker 客户端。
- Docker 客户端再次使用从 API 收到的令牌登录。经过身份验证的客户端现在可以推送和拉取 Docker 镜像。
参考:https://distribution.github.io/distribution/spec/auth/token/
GitLab 与容器注册表之间的通信
容器注册表无法内部验证用户身份,因此它通过 GitLab 验证凭据。注册表与 GitLab 之间的连接是 TLS 加密的。
GitLab 使用私钥签署令牌,而注册表使用证书提供的公钥来验证签名。
默认情况下,所有安装都会生成自签名证书密钥对。你可以通过注册表配置中的 internal_key 设置覆盖此行为。
以下步骤描述了通信流程:
- GitLab 使用注册表的私钥与注册表交互。当发送注册表请求时,会生成一个短期的(10 分钟)、命名空间受限的令牌,并使用私钥对其进行签名。
- 注册表验证签名是否与其配置中指定的注册表证书匹配,并允许操作。
- GitLab 通过 Sidekiq 处理后台作业,这些作业也与注册表交互。这些作业直接与注册表通信以处理镜像删除。
从第三方注册表迁移
在 GitLab 中使用外部容器注册表的功能已在 GitLab 15.8 中被弃用,并在 GitLab 16.0 中停止支持。有关更多详情,请参阅弃用通知。
该集成在 GitLab 16.0 中并未被禁用,但对调试和修复问题的支持已不再提供。此外,该集成也不再进行开发或添加新功能。在新的 GitLab 容器注册表版本可供 GitLab 自托管版使用后(参见 epic 5521),第三方注册表功能可能会被完全移除。目前仅计划支持 GitLab 容器注册表。
本节提供了管理员从第三方注册表迁移至 GitLab 容器注册表的指南。如果您使用的第三方容器注册表未在此列出,可以在反馈问题中描述您的用例。
对于以下所有说明,您应先在测试环境中尝试。在生产环境中复制之前,请确保一切按预期正常工作。
Docker Distribution 注册表
Docker Distribution 注册表 已捐赠给 CNCF,现称为 Distribution 注册表。此注册表是 GitLab 容器注册表所基于的开源实现。GitLab 容器注册表与 Distribution 注册表提供的基本功能兼容,包括所有支持的存储后端。若要迁移至 GitLab 容器注册表,您可以遵循本页面的说明,并使用与 Distribution 注册表相同的存储后端。GitLab 容器注册表应接受您为 Distribution 注册表使用的相同配置。
删除容器镜像的最大重试次数
删除容器镜像时可能出现错误,因此会重试删除操作以确保错误并非暂时性问题。删除操作最多重试 10 次,每次重试之间有退避延迟。此延迟为任何暂时性错误的解决提供了更长时间。
设置最大重试次数也有助于检测在重试期间是否解决了任何持久性问题。当删除失败达到最大重试次数后,容器仓库的 status 将被设置为 delete_failed。处于此状态下,仓库将不再重试删除操作。
您应调查具有 delete_failed 状态的任何容器仓库并尝试解决问题。问题解决后,您可以将仓库状态重新设置为 delete_scheduled,以便图像可以再次开始删除。要从 Rails 控制台更新仓库状态:
container_repository = ContainerRepository.find(<id>)
container_repository.update(status: 'delete_scheduled')