- 启用容器镜像库
- 容器镜像库域名配置
- 在站点范围内禁用容器镜像库
- 在站点中的新项目范围内禁用 Container Registry
- 配置容器镜像库的存储
- 更改镜像库的内部端口
- 禁用某个项目的容器镜像库
- 使用外部容器镜像库作为身份验证端点
- 配置容器镜像库通知
- 立即运行清理策略
- 容器镜像库垃圾回收
- 配置 GitLab 和 Registry 在不同的节点上运行(Omnibus GitLab)
- GitLab Container Registry 的架构
- 故障排查
极狐GitLab 容器镜像库管理
使用极狐GitLab 容器镜像库,每个项目都可以拥有自己的空间来存储 Docker 镜像。
在 Docker 文档 中阅读有关 Docker Registry 的更多信息。
本文档是管理员指南。
启用容器镜像库
Omnibus 安装实例
如果您使用 Omnibus 安装包安装 GitLab,则默认情况下容器镜像库可能可用,也可能不可用。
在以下情况下,容器镜像库会自动启用并在您的 GitLab 域名端口 5050 上可用:
- 您正在使用内置的 Let’s Encrypt 集成,并且
- 您使用的是 12.5 或更高版本。
否则,不可启用容器镜像库。要启用它:
- 您可以为您的极狐GitLab 域名配置,或者
- 您可以为不同的域名配置。
容器镜像库默认在 HTTPS 下工作。 您可以使用 HTTP,但不推荐使用,并且超出了本文档的范围。 如果您想这样做,请阅读 insecure Registry 文档。
源安装实例
如果您已从源代码安装极狐GitLab:
- 必须自行安装 Registry。
- 安装完成后,要启用它,必须在
gitlab.yml
中配置 Registry。 - 使用
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 Registry,否则请勿更改此设置。
|
key
| 私钥位置是一对 Registry 的 rootcertbundle 。 阅读 token auth 配置文档。
|
path
| 应与 Registry 的 rootdirectory 中指定的目录相同。 阅读存储配置文档。该路径需要 GitLab 用户、Web 服务器用户和 Registry 用户可读。 阅读相关文档了解更多信息。
|
issuer
| 应与在 Registry 的 issuer 中配置的值相同。 阅读 token auth 配置文档。
|
如果您从源代码安装,则极狐GitLab 不会附带 Registry init 文件。 因此,如果您修改 Registry 设置,重新启动 GitLab 不会重新启动 Registry。阅读有关如何实现这一目标的上游文档。
要进行绝对最小配置,确保您的 Registry 配置中有 container_registry
作为服务并且有 https://gitlab.example.com/jwt/auth
作为 Realm:
auth:
token:
realm: https://gitlab.example.com/jwt/auth
service: container_registry
issuer: gitlab-issuer
rootcertbundle: /root/certs/certbundle
auth
,用户可以在没有身份验证的情况下拉取 Docker 镜像。容器镜像库域名配置
有两种方法可以配置镜像库的外部域名:
-
使用现有的 GitLab 域名。Registry 侦听端口并重用来自 GitLab 的 TLS 证书。
-
使用完全独立的域名以及该域的新 TLS 证书。
由于容器镜像库需要 TLS 证书,因此成本可能是一个考虑因素。
在首次配置容器镜像库之前,请考虑这一点。
使用现有的 GitLab 域名配置容器镜像库
如果注册表配置为使用现有的 GitLab 域名,您可以在端口上公开镜像库。这样您就可以重用现有的 GitLab TLS 证书。
如果 GitLab 域是 https://gitlab.example.com
并且对外的端口是 5050
,使用 Omnibus GitLab 安装时,在 gitlab.rb
中配置;使用源安装时,在 gitlab.yml
中配置。
确保您选择的端口与 Registry 侦听的端口不同(默认为 5000
),否则会发生冲突。
Omnibus 安装
-
您的
/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 证书文件。
源安装
-
打开
/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
使用独立的域名配置容器镜像库
当 Registry 配置为使用自己的域名时,您需要该特定域名的 TLS 证书(例如,registry.example.com
)。 如果托管在现有 GitLab 域名的子域下,您可能需要通配符证书,例如,registry.gitlab.example.com
。
除了手动生成的 SSL 证书(在此处说明),Let’s Encrypt 自动生成的证书也支持在 Omnibus 安装中使用。
假设您希望容器镜像库可通过 https://registry.gitlab.example.com
访问。
Omnibus 安装
-
将您的 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 镜像。 这是由 Registry 应用程序本身处理的。
Omnibus 安装
-
打开
/etc/gitlab/gitlab.rb
并将registry['enable']
设置为false
:registry['enable'] = false
-
保存文件并重新配置极狐GitLab 以使更改生效。
源安装e
-
打开
/home/git/gitlab/config/gitlab.yml
,找到registry
条目并将enabled
设置为false
:registry: enabled: false
-
保存文件并重新启动极狐GitLab 以使更改生效。
在站点中的新项目范围内禁用 Container Registry
如果容器镜像库已启用,则它应该可用于所有新项目。 要禁用此功能并让项目所有者自行启用容器镜像库,请按照以下步骤操作。
Omnibus 安装
-
编辑
/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 project features settings default_projects_features: issues: true merge_requests: true wiki: true snippets: false builds: true container_registry: false
-
保存文件并重新启动极狐GitLab 以使更改生效。
增加令牌期限
在极狐GitLab 中,容器镜像库的令牌每五分钟过期一次。 要增加令牌期限:
- 在顶部栏上,选择 菜单 > 管理员。
- 在左侧边栏,选择 设置 > CI/CD。
- 展开 容器镜像库。
- 对于 授权令牌期限(分钟),更新数值。
- 选择 保存更改。
配置容器镜像库的存储
您可以通过配置存储驱动程序来配置容器镜像库以使用各种存储后端。默认情况下 GitLab 容器镜像库配置为使用文件系统驱动程序。
支持的驱动程序包括:
驱动程序 | 说明 |
---|---|
filesystem
| 使用本地文件系统路径 |
azure
| Microsoft Azure Blob Storage |
gcs
| Google Cloud Storage |
s3
| Amazon Simple Storage Service。请务必使用正确的 S3 权限范围 配置您的存储桶。 |
swift
| OpenStack Swift 对象存储 |
oss
| Aliyun OSS |
尽管大多数与 S3 兼容的服务(如 MinIO)应与 容器镜像库配合使用,但我们仅保证支持 AWS S3。
阅读有关各个驱动程序配置选项的更多信息,查看 Docker Registry 文档。
使用文件系统
如果您想将您的镜像存储在文件系统上,您可以更改容器镜像库的存储路径,请按照以下步骤操作。
路径应可供以下人员访问:
- 运行容器镜像库守护进程的用户。
- 运行 GitLab 的用户
所有 GitLab、Registry 和 Web 服务器用户都必须可以访问这个目录。
Omnibus 安装
Omnibus 安装实例中,存储镜像的默认位置是 /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 以使更改生效。
使用对象存储
如果要将镜像存储在对象存储上,可以更改容器镜像库的存储驱动程序。
Omnibus 安装
要在 Omnibus 中配置 s3
存储驱动程序:
-
编辑
/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' } }
为避免使用静态凭证,请使用 IAM 角色 并省略
accesskey
和secretkey
。 确保您的 IAM 配置文件遵循 Docker 记录的权限。registry['storage'] = { 's3' => { 'bucket' => 'your-s3-bucket', 'region' => 'your-s3-region' } }
如果与 AWS S3 VPC 终端节点 一起使用,则将
regionendpoint
设置为您的 VPC 终端节点地址并设置pathstyle
为 false: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-vpc-endpoint', 'pathstyle' => false } }
- 只有在配置 S3 兼容服务(例如 MinIO)或使用 AWS S3 VPC 端点时才需要
regionendpoint
。 -
your-s3-bucket
应该是存在的存储桶的名称,并且不能包含子目录。 -
pathstyle
应该设置为 true,以使用host/bucket_name/object
样式路径而不是bucket_name.host/object
。AWS S3 设置为 false。
您可以设置与 S3 的连接的速率限制,避免来自 S3 API 的 503 错误。请将
maxrequestspersecond
设置为 [S3 请求速率阈值] (https://aws.amazon.com/premiumsupport/knowledge-center/s3-503-within-request-rate-prefix/)内的数字: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 } }
- 只有在配置 S3 兼容服务(例如 MinIO)或使用 AWS S3 VPC 端点时才需要
-
保存文件并重新配置极狐GitLab 以使更改生效。
源安装
配置存储驱动程序是在您部署 Docker 注册表 时创建的镜像库配置 YAML 文件中完成的。
s3
存储驱动程序示例:
storage:
s3:
accesskey: 's3-access-key' # Not needed if IAM role used
secretkey: 's3-secret-key-for-access-key' # Not needed if IAM role used
bucket: 'your-s3-bucket'
region: 'your-s3-region'
regionendpoint: 'your-s3-regionendpoint'
cache:
blobdescriptor: inmemory
delete:
enabled: true
your-s3-bucket
应该是存在的存储桶的名称,并且不能包含子目录。
零停机迁移到对象存储
要在不停止容器镜像库的情况下迁移存储,请将容器镜像库设置为只读模式。在大型实例中,这可能需要容器镜像库处于只读模式一段时间。在此期间,您可以从容器镜像库中拉取,但无法推送。
- 可选:为了减少需要迁移的数据量,运行无停机垃圾收集工具。
-
此示例使用
aws
CLI。 如果您之前未配置 CLI,则必须通过运行sudo aws configure
来配置您的凭据。由于非管理员用户可能无法访问容器镜像库文件夹,因此请确保使用sudo
。 要检查您的凭证配置,请运行ls
以列出所有存储桶。sudo aws --endpoint-url https://your-object-storage-backend.com s3 ls
如果您使用 AWS 作为后端,则不需要
--endpoint-url
。 -
将初始数据复制到您的 S3 存储桶,例如使用
aws
CLIcp
或sync
命令。 确保将docker
文件夹作为存储桶内的顶级文件夹。sudo aws --endpoint-url https://your-object-storage-backend.com s3 sync registry s3://mybucket
如果您有大量数据,您或许可以通过运行并行同步操作来提高性能。 -
要执行最终的数据同步,将容器镜像库置于
只读
模式,并重新配置极狐GitLab。 -
将初始数据加载到 S3 存储桶后的任何更改同步,并删除目标存储桶中存在但源中不存在的文件:
sudo aws --endpoint-url https://your-object-storage-backend.com s3 sync registry s3://mybucket --delete --dryrun
验证命令按预期执行后,删除
--dryrun
标志并运行命令。--delete
标志删除目标中存在但源中不存在的文件。 如果交换源和目标,则镜像库中的所有数据都将被删除。 -
通过查看以下两个命令返回的文件计数,验证所有容器镜像仓库文件都已上传到对象存储:
sudo find registry -type f | wc -l
sudo aws --endpoint-url https://your-object-storage-backend.com s3 ls s3://mybucket --recursive | wc -l
这些命令的输出应该匹配,除了
_uploads
目录和子目录中的内容。 -
将您的注册表配置为使用 S3 存储桶进行存储。
- 为了使更改生效,将注册表设置回
读写
模式并重新配置极狐GitLab。
禁用存储驱动程序的重定向
默认情况下,访问配置有远程后端的镜像库的用户,被重定向到存储驱动程序的默认后端。例如,可以使用 s3
存储驱动程序配置镜像库,它将请求重定向到远程 S3 存储桶以减轻 GitLab 服务器上的负载。
但是,对于通常无法访问公共服务器的内部主机使用的镜像库,这种行为是不可取的。要禁用重定向和代理下载,请将 disable
标志设置为 true,如下所示。 这使得所有流量始终通过 Registry 服务。 这会提高安全性(减少表面攻击,因为存储后端不可公开访问),但性能更差(所有流量都通过服务重定向)。
Omnibus 安装
-
编辑
/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: 'AKIAKIAKI' secretkey: 'secret123' bucket: 'gitlab-registry-bucket-AKIAKIAKI' region: 'your-s3-region' regionendpoint: 'your-s3-regionendpoint' redirect: disable: true cache: blobdescriptor: inmemory delete: enabled: true
-
保存文件并重新启动极狐GitLab 以使更改生效。
加密的 S3 存储桶
您可以将 AWS KMS 服务器端加密用于默认启用 SSE-S3 或 SSE-KMS 加密的 S3 存储桶。 不支持客户主密钥 (CMK) 和 SSE-C 加密,因为这需要在每个请求中发送加密密钥。
对于 SSE-S3,您必须在注册表设置中启用 encrypt
选项。 您如何执行此操作取决于您安装极狐GitLab 的方式。 按照此处与您的安装方法相匹配的说明进行操作。
对于 Omnibus 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: 'AKIAKIAKI' secretkey: 'secret123' bucket: 'gitlab-registry-bucket-AKIAKIAKI' region: 'your-s3-region' regionendpoint: 'your-s3-regionendpoint' encrypt: true
-
保存文件并重新启动极狐GitLab 以使更改生效。
存储限制
目前没有存储限制,这意味着用户可以上传无限数量的任意大小的 Docker 镜像。
更改镜像库的内部端口
默认情况下,Registry 服务器在端口 5000
上侦听本地主机,这是 Registry 服务器应接受连接的地址。
在下面的示例中,我们将 Registry 的端口设置为 5010
。
Omnibus 安装
-
打开
/etc/gitlab/gitlab.rb
并设置registry['registry_http_addr']
:registry['registry_http_addr'] = "localhost:5010"
-
保存文件并重新配置极狐GitLab 以使更改生效。
源安装
-
打开 Registry 服务器的配置文件并编辑
http:addr
值:http: addr: localhost:5010
-
保存文件并重新启动 Registry 服务器。
禁用某个项目的容器镜像库
如果在您的 GitLab 实例中启用了 Registry,但您的项目不需要它,您可以在项目的设置中禁用。
使用外部容器镜像库作为身份验证端点
如果您使用外部容器镜像库,则与容器镜像库关联的某些功能可能不可用,或具有固有风险。
要使集成工作,必须将外部镜像库配置为使用 JSON Web 令牌向极狐GitLab 进行身份验证。外部镜像库的运行时配置 必须具有以下条目:
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
。
Omnibus 安装
您可以将极狐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
。 阅读有关 Docker Registry 文档 的更多信息。
- 需要
-
GitLab 和外部容器镜像库需要证书密钥对才能安全通信。您需要创建一个证书密钥对,使用公共证书(
rootcertbundle
)配置外部容器镜像库,并使用私钥配置 GitLab。为此,请将以下内容添加到/etc/gitlab/gitlab.rb
:# registry['internal_key'] should contain the contents of the custom key # file. Line breaks in the key file should be marked using `\n` character # Example: registry['internal_key'] = "---BEGIN RSA PRIVATE KEY---\nMIIEpQIBAA\n" # Optionally define a custom file for Omnibus GitLab to write the contents # of registry['internal_key'] to. gitlab_rails['registry_key_path'] = "/custom/path/to/registry-key.key"
每次执行重新配置时,
registry_key_path
中指定的文件都会填充有internal_key
指定的内容。 如果未指定文件,Omnibus GitLab 会将其默认为/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
进行以下配置:## Container 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 Registry 通知文档 中阅读有关容器镜像库通知配置选项的更多信息。
您可以为容器镜像库配置多个端点。
Omnibus 安装
要在 Omnibus 中配置通知端点:
-
编辑
/etc/gitlab/gitlab.rb
:registry['notifications'] = [ { 'name' => 'test_endpoint', 'url' => 'https://gitlab.example.com/notify', 'timeout' => '500ms', 'threshold' => 5, 'backoff' => '1s', 'headers' => { "Authorization" => ["AUTHORIZATION_EXAMPLE_TOKEN"] } } ]
-
保存文件并重新配置极狐GitLab 以使更改生效。
源安装
配置通知端点是在您部署 Docker Registry 时创建的镜像库中配置的 YAML 文件中完成的。
示例:
notifications:
endpoints:
- name: alistener
disabled: false
url: https://my.listener.com/event
headers: <http.Header>
timeout: 500
threshold: 5
backoff: 1000
立即运行清理策略
gitlab.rb
文件以指向正确的仓库 URL,并将 registry.key
文件复制到每个 Sidekiq 节点。
为了减少给定项目使用的容器镜像库磁盘空间,管理员可以清理镜像标签和运行垃圾收集。
要通过运行清理策略删除图像标签,请在 GitLab Rails 控制台中运行以下命令:
# Numeric ID of the project whose container registry should be cleaned up
P = <project_id>
# Numeric ID of a user with Developer, Maintainer, or Owner role for the project
U = <user_id>
# Get required details / objects
user = User.find_by_id(U)
project = Project.find_by_id(P)
policy = ContainerExpirationPolicy.find_by(project_id: P)
# Loop through each container repository
project.container_repositories.find_each do |repo|
puts repo.attributes
# Start the tag cleanup
puts Projects::ContainerRepository::CleanupTagsService.new(repo, user, policy.attributes.except("created_at", "updated_at")).execute(repo)
end
您还可以按计划运行清理。
容器镜像库垃圾回收
容器镜像库可能会使用大量磁盘空间。为了清除一些未使用的层,注册表包含一个垃圾收集命令。
GitLab 提供了一组 API 来操作容器注册表并帮助删除未使用的标签。 目前,这是使用 API 公开的,但将来,这些控件应该迁移到 GitLab 界面。
项目维护人员可以根据自己的标准定期批量删除 Container Registry 标签,但是,这本身并不会回收数据,它仅从 manifests 和镜像 blob 中取消链接标签。要回收整个 GitLab 实例中的容器镜像库数据,可以使用 gitlab-ctl
提供的内置命令。
前提条件:
- 您必须使用 Omnibus 包或 云原生 Chart 安装极狐GitLab。
- 您必须将镜像库设置为只读模式。运行垃圾回收会导致容器镜像库停机。当另一个实例仍在向运行命令的实例写入镜像库存储,同时您运行此命令时,将删除引用的 manifests。
了解内容可寻址层
考虑以下示例,您首先在其中构建镜像:
# This builds a image with content of sha256:111111
docker build -t my.registry.com/my.group/my.project:latest .
docker push my.registry.com/my.group/my.project:latest
现在,您用新版本覆盖了 :latest
:
# This builds a image with content of 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
的 manifest。但是,由于镜像库的架构,即使不再通过 :latest
标签直接访问该数据,在拉取镜像 my.registry.com/my.group/my.project@sha256:111111
时,仍然可以访问数据。
回收未使用的标签
在运行内置命令之前,请注意以下事项:
- 内置命令在开始垃圾收集之前停止镜像库。
- 垃圾收集命令需要一些时间才能完成,具体取决于存在的数据量。
- 如果更改了镜像库配置文件的位置,则必须指定其路径。
- 垃圾收集完成后,镜像库应自动启动。
如果您没有更改配置文件的默认位置,请运行以下命令:
sudo gitlab-ctl registry-garbage-collect
此命令需要一些时间才能完成,具体取决于您存储的镜像层数量。
如果您更改了容器镜像库 config.yml
的位置:
sudo gitlab-ctl registry-garbage-collect /path/to/config.yml
您也可以删除所有未标记的制品和未引用的层,尽管这是一种更具破坏性的操作,您应该首先了解其含义。
删除未标记的制品和未引用的层
GitLab 容器镜像库遵循与 Docker Distribution 相同的默认工作流程:保留未标记的制品和所有层,即使是未直接引用的层。可以使用上下文可寻址标识符访问所有内容。
但是,在大多数工作流中,您不会关心未标记制品和旧层是否被标记的制品直接引用。registry-garbage-collect
命令支持 -m
开关,允许您删除所有无法通过 tag
直接访问的未引用制品和层:
sudo gitlab-ctl registry-garbage-collect -m
由于这是一种更具破坏性的操作,因此默认情况下禁用。 您可能期望这种操作方式,但在此之前,请确保您已备份所有镜像库数据。
在不停机的情况下执行垃圾收集
通过将容器镜像库置于只读模式并且不使用内置命令,您可以在不停止容器镜像库的情况下执行垃圾收集。在大型实例中,这可能需要容器镜像库处于只读模式一段时间。在此期间,您可以从容器镜像库中拉取,但无法推送。
默认情况下,镜像库存储路径是 /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
此命令将容器镜像库设置为只读模式。
-
接下来,触发垃圾收集命令之一:
# Recycling unused tags sudo /opt/gitlab/embedded/bin/registry garbage-collect /var/opt/gitlab/registry/config.yml # Removing unused layers not referenced by manifests 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
# Run every Sunday at 04:05am
5 4 * * 0 root gitlab-ctl registry-garbage-collect
您可能希望将 -m
标志添加到删除未标记的制品和未引用的层。
停止垃圾收集
如果您希望停止垃圾回收,您应该按照在不停机的情况下进行垃圾收集 中的说明,手动运行垃圾收集。 然后您可以按 Control+C 停止垃圾收集。
否则,中断 gitlab-ctl
可能会使您的 registry 服务处于关闭状态。 在这种情况下,你必须找到在系统上的垃圾收集进程,以便 gitlab-ctl
命令可以重新启动 registry 服务。
此外,在进程的标记阶段无法保存进度或结果。只有当 blob 开始被删除时,才会永久完成。
配置 GitLab 和 Registry 在不同的节点上运行(Omnibus GitLab)
默认情况下,软件包假定两个服务都在同一节点上运行。为了让 GitLab 和 Registry 在单独的节点上运行,需要对 Registry 和 GitLab 进行单独配置。
配置 Registry
下面是您应该在 /etc/gitlab/gitlab.rb
中设置的配置选项,以便 Registry 与 GitLab 分开运行:
-
registry['registry_http_addr']
,以编程方式设置默认值。需要可以通过 Web 服务器(或 LB)访问。 -
registry['token_realm']
,以编程方式设置默认值。指定用于执行身份验证的端点,通常是 GitLab URL。此端点需要用户可以访问。 -
registry['http_secret']
,随机字符串。用于对状态进行签名的随机数据,可以与客户端一起存储以防止篡改。 -
registry['internal_key']
,自动生成默认值。GitLab 用于对令牌进行签名的密钥的内容。它们的密钥是在 Registry 服务器上创建的,但不会在那里使用。 -
gitlab_rails['registry_key_path']
,以编程方式设置默认值。这是将internal_key
内容写入磁盘的路径。 -
registry['internal_certificate']
,自动生成默认值。GitLab 用于签署令牌的证书内容。 -
registry['rootcertbundle']
,以编程方式设置默认值。证书路径,是将internal_certificate
内容写入磁盘的路径。 -
registry['health_storagedriver_enabled']
,以编程方式设置默认值。配置是否启用对配置的存储驱动程序的健康检查。 -
gitlab_rails['registry_issuer']
, 默认值。此设置需要在 Registry 和 GitLab 之间设置相同。
配置 GitLab
下面是应该在 /etc/gitlab/gitlab.rb
中设置的配置选项,以便 GitLab 与 Registry 分开运行:
-
gitlab_rails['registry_enabled']
,必须设置为true
。 此设置将向 GitLab 发出信号,表明它应该允许 Registry API 请求。 -
gitlab_rails['registry_api_url']
,默认以编程方式设置。这是内部使用的 Registry URL,用户不需要与之交互,而是与registry['registry_http_addr']
。 -
gitlab_rails['registry_host']
,例如registry.gitlab.example
。没有 scheme 的 Registry 端点,显示给最终用户的地址。 -gitlab_rails['registry_port']
。Registry 端点端口,对最终用户可见。 -
gitlab_rails['registry_issuer']
必须与 Registry 配置中的颁发者相匹配。 -
gitlab_rails['registry_key_path']
,与 Registry 端证书匹配的密钥的路径。 -
gitlab_rails['internal_key']
,GitLab 用于签署令牌的密钥内容。
GitLab Container Registry 的架构
GitLab Registry 是用户用来存储他们自己的 Docker 镜像的地方。由于 Registry 是面向客户端的,我们直接在 Web 服务器(或负载均衡器,简称 LB)上公开它。
上图描述的流程:
- 用户在他们的客户端上运行
docker login registry.gitlab.example
。通过端口 443 到达 Web 服务器(或 LB)。 - Web 服务器连接到 Registry 后端池(默认使用端口 5000)。由于用户没有提供有效的令牌,Registry 返回 401 HTTP 代码和 URL(来自 Registry 配置的
token_realm
)从哪里获取。这指向 GitLab API。 - Docker 客户端然后连接到 GitLab API 并获取令牌。
- API 使用 registry key对令牌进行签名,并将其交给 Docker 客户端。
- Docker 客户端现在使用从 API 收到的令牌再次登录。现在可以推送和拉取 Docker 镜像。
参考:https://docs.docker.com/registry/spec/auth/token/
GitLab 和 Registry 之间的通信
Registry 无法在内部对用户进行身份验证,因此它依赖 GitLab 来验证凭据。Registry 和 GitLab 之间的连接是 TLS 加密的。GitLab 使用密钥对令牌进行签名,而 Registry 使用证书来验证签名。默认情况下,会为所有安装生成自签名证书密钥对。可以根据需要被覆盖。
GitLab 使用 Registry 私钥与 Registry 交互。当 Registry 请求发出时,会生成一个新的短期(10 分钟)命名空间受限令牌并使用私钥进行签名。然后,Registry 验证签名是否与其配置中指定的 Registry 证书匹配并允许操作。GitLab 后台作业处理(通过 Sidekiq)也与 Registry 交互。这些作业直接与 Registry 对话以处理镜像删除。
故障排查
在深入研究以下部分之前,查看一些基本的故障排除信息:
-
检查以确保 Docker 客户端和 GitLab 服务器上的系统时钟已同步(例如通过 NTP)。
-
如果您使用的是 S3 支持的镜像库,请仔细检查 IAM 权限和 S3 凭证(包括区域)是否正确。有关更多详细信息,请参阅示例 IAM 策略。
-
检查镜像库日志(例如
/var/log/gitlab/registry/current
)和 GitLab 生产日志是否有错误(例如/var/log/gitlab/gitlab-rails/production.log
)。您或许可以在那里找到线索。
将自签名证书与容器镜像库结合使用
如果您在容器镜像库中使用自签名证书,则在 CI 作业期间可能会遇到如下问题:
Error response from daemon: Get registry.example.com/v1/users/: x509: certificate signed by unknown authority
运行该命令的 Docker 守护进程需要由公认的 CA 签名的证书,因此出现上述错误。
虽然不支持在容器镜像库中使用开箱即用的自签名证书,但可以通过指示 Docker 守护进程信任自签名证书,挂载 Docker 守护进程并在 GitLab Runner 的 config.toml
文件中设置 privileged = false
。 设置 privileged = true
优先于 Docker 守护进程:
[runners.docker]
image = "ruby:2.6"
privileged = false
volumes = ["/var/run/docker.sock:/var/run/docker.sock", "/cache"]
Docker 登录尝试失败并显示:’token signed by untrusted key’
Registry 依赖极狐GitLab 来验证凭据。如果镜像库验证登录尝试失败,您会收到以下错误消息:
# docker login gitlab.company.com:4567
Username: user
Password:
Error response from daemon: login attempt to https://gitlab.company.com:4567/v2/ failed with status: 401 Unauthorized
更具体地说,这出现在 /var/log/gitlab/registry/current
日志文件中:
level=info msg="token signed by untrusted key with ID: "TOKE:NL6Q:7PW6:EXAM:PLET:OKEN:BG27:RCIB:D2S3:EXAM:PLET:OKEN""
level=warning msg="error authorizing context: invalid token" go.version=go1.12.7 http.request.host="gitlab.company.com:4567" http.request.id=74613829-2655-4f96-8991-1c9fe33869b8 http.request.method=GET http.request.remoteaddr=10.72.11.20 http.request.uri="/v2/" http.request.useragent="docker/19.03.2 go/go1.12.8 git-commit/6a30dfc kernel/3.10.0-693.2.2.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.2 \(linux\))"
GitLab 使用证书密钥对两侧的内容为 Registry 加密身份验证令牌。此消息表示这些内容未匹配。
检查正在使用的文件:
-
grep -A6 'auth:' /var/opt/gitlab/registry/config.yml
## Container Registry Certificate auth: token: realm: https://<example_url>/jwt/auth service: container_registry issuer: omnibus-gitlab-issuer --> rootcertbundle: /var/opt/gitlab/registry/gitlab-registry.crt autoredirect: false
-
grep -A9 'Container Registry' /var/opt/gitlab/gitlab-rails/etc/gitlab.yml
## Container Registry Key registry: enabled: true host: gitlab.company.com port: 4567 api_url: http://127.0.0.1:5000 # internal address to the registry, will be used by GitLab to directly communicate with API path: /var/opt/gitlab/gitlab-rails/shared/registry --> key: /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key issuer: omnibus-gitlab-issuer notification_secret:
这些 openssl
命令的输出应该匹配,证明 cert-key 对是匹配的:
openssl x509 -noout -modulus -in /var/opt/gitlab/registry/gitlab-registry.crt | openssl sha256
openssl rsa -noout -modulus -in /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key | openssl sha256
如果证书的两部分不匹配,请删除文件并运行 gitlab-ctl reconfigure
以重新生成证书对。如果存在,则使用 /etc/gitlab/gitlab-secrets.json
中的现有值重新创建证书对。要生成新的证书对,请在运行 gitlab-ctl reconfigure
之前删除 /etc/gitlab/gitlab-secrets.json
中的 registry
部分。
如果您使用自己的证书覆盖了自动生成的自签名对,并确保它们的内容匹配,则可以删除 /etc/gitlab/gitlab-secrets.json
中的 registry
部分并运行 gitlab -ctl reconfigure
。
推送大镜像时,AWS S3 出现极狐GitLab 镜像库错误
在 GitLab 镜像库中使用 AWS S3 时,推送大镜像时可能会发生错误。在镜像库日志中查看以下错误:
level=error msg="response completed with error" err.code=unknown err.detail="unexpected EOF" err.message="unknown error"
要解决该错误,请在镜像库配置中指定一个 chunksize
值。 从 25000000
(25MB) 和 50000000
(50MB) 之间的值开始。
Omnibus 安装
-
编辑
/etc/gitlab/gitlab.rb
:registry['storage'] = { 's3' => { 'accesskey' => 'AKIAKIAKI', 'secretkey' => 'secret123', 'bucket' => 'gitlab-registry-bucket-AKIAKIAKI', 'chunksize' => 25000000 } }
-
保存文件并重新配置极狐GitLab 以使更改生效。
源安装
-
编辑
config/gitlab.yml
:storage: s3: accesskey: 'AKIAKIAKI' secretkey: 'secret123' bucket: 'gitlab-registry-bucket-AKIAKIAKI' chunksize: 25000000
-
保存文件并重新启动极狐GitLab 以使更改生效。
支持较旧的 Docker 客户端
极狐GitLab 附带的 Docker 容器镜像库默认禁用 schema1 manifest。如果您仍在使用较旧的 Docker 客户端(1.9 或更早版本),您可能会在推送镜像时遇到错误。
您可以添加配置选项以实现向后兼容性。
Omnibus 安装
-
编辑
/etc/gitlab/gitlab.rb
:registry['compatibility_schema1_enabled'] = true
-
保存文件并重新配置极狐GitLab 以使更改生效。
源安装
-
编辑您在部署镜像库 时创建的 YAML 配置文件。 添加以下代码段:
compatibility: schema1: enabled: true
-
重新启动镜像库以使更改生效。
Docker 连接错误
当群组、项目或分支名称中存在特殊字符时,可能会发生 Docker 连接错误。特殊字符包括:
- 前置下划线
- 后置连字符/破折号
- 双连字符/破折号
要解决此问题,您可以更改群组路径、更改项目路径或更改分支名称。另一种选择是创建推送规则,在实例级别防止这种情况。
镜像推送错误
当 docker login
工作正常时,尝试推送镜像出现错误或 “retrying” 循环,NGINX 转发到镜像库的 header 可能存在问题。默认推荐的 NGINX 配置应该可以解决这个问题,但它可能发生在 SSL 被卸载到第三方反向代理的自定义设置中。
一个简单的解决方案是在镜像库中启用相对 URL。
Omnibus 安装
-
编辑
/etc/gitlab/gitlab.rb
:registry['env'] = { "REGISTRY_HTTP_RELATIVEURLS" => true }
-
保存文件并重新配置极狐GitLab 以使更改生效。
源安装
-
编辑您在部署镜像库时创建的 YAML 配置文件。 添加以下代码段:
http: relativeurls: true
-
保存文件并重新启动极狐GitLab 以使更改生效。
启用 Registry debug 服务器
您可以使用容器镜像库调试服务器来诊断问题。调试端点可以监控指标和运行状况,以及进行分析。
可以通过在 gitlab.rb
配置中设置镜像库调试地址,启用可选的 debug 服务器。
registry['debug_addr'] = "localhost:5001"
添加设置后,重新配置极狐GitLab 以应用更改。
使用 curl 从调试服务器请求调试输出:
curl "localhost:5001/debug/health"
curl "localhost:5001/debug/vars"
高级故障排查
我们用一个具体的例子来说明如何诊断 S3 设置的问题。
调查清理策略
如果您不确定您的清理策略为何删除或未删除标签,请通过从 Rails 控制台运行以下脚本逐行执行该策略。 这可以帮助诊断策略问题。
repo = ContainerRepository.find(<project_id>)
policy = repo.project.container_expiration_policy
tags = repo.tags
tags.map(&:name)
tags.reject!(&:latest?)
tags.map(&:name)
regex_delete = ::Gitlab::UntrustedRegexp.new("\\A#{policy.name_regex}\\z")
regex_retain = ::Gitlab::UntrustedRegexp.new("\\A#{policy.name_regex_keep}\\z")
tags.select! { |tag| regex_delete.match?(tag.name) && !regex_retain.match?(tag.name) }
tags.map(&:name)
now = DateTime.current
tags.sort_by! { |tag| tag.created_at || now }.reverse! # Lengthy operation
tags = tags.drop(policy.keep_n)
tags.map(&:name)
older_than_timestamp = ChronicDuration.parse(policy.older_than).seconds.ago
tags.select! { |tag| tag.created_at && tag.created_at < older_than_timestamp }
tags.map(&:name)
- 脚本构建要删除的标签列表(
tags
)。 -
tags.map(&:name)
打印要删除的标签列表。这可能是一个漫长的操作。 - 在每个过滤器之后,检查
tags
列表,查看它是否包含要销毁的预期标签。
推送时遇到 Unexpected 403 error
用户尝试启用 S3 支持的镜像库。 docker login
步骤进行得很顺利。但是,在推送镜像时,输出显示:
The push refers to a repository [s3-testing.myregistry.com:5050/root/docker-test/docker-image]
dc5e59c14160: Pushing [==================================================>] 14.85 kB
03c20c1a019a: Pushing [==================================================>] 2.048 kB
a08f14ef632e: Pushing [==================================================>] 2.048 kB
228950524c88: Pushing 2.048 kB
6a8ecde4cc03: Pushing [==> ] 9.901 MB/205.7 MB
5f70bf18a086: Pushing 1.024 kB
737f40e80b7f: Waiting
82b57dbc5385: Waiting
19429b698a22: Waiting
9436069b92a3: Waiting
error parsing HTTP 403 response body: unexpected end of JSON input: ""
这个错误是模棱两可的,因为不清楚 403 是来自 GitLab Rails 应用程序、Docker Registry 还是其它组件。在这种情况下,由于我们知道登录成功了,大概就需要查看客户端和 Registry 的通信。
在 Docker 文档中 描述了 Docker 客户端和 Registry 之间的 REST API。通常会使用 Wireshark 或 tcpdump 来捕获流量并查看哪里出了问题。但是,由于 Docker 客户端和服务器之间的所有通信都是通过 HTTPS 完成的,因此即使您知道私钥,也很难快速解密流量。我们能做些什么呢?
一种方法是通过设置不安全镜像库 来禁用 HTTPS。 这可能会引入安全漏洞,仅建议用于本地测试。如果您有一个生产系统并且不能或不想这样做,还有另一种方法:使用 mitmproxy,作为中间人代理。
mitmproxy
mitmproxy 允许您在客户端和服务器之间放置代理以检查所有流量。 一个问题是您的系统需要信任 mitmproxy SSL 证书才能使其工作。
以下安装说明假设您正在运行 Ubuntu:
- 安装 mitmproxy。
- 运行
mitmproxy --port 9000
来生成它的证书。输入 CTRL-C 退出。 -
从
~/.mitmproxy
安装证书到你的系统:sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem /usr/local/share/ca-certificates/mitmproxy-ca-cert.crt sudo update-ca-certificates
如果成功,输出应表明已添加证书:
Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.
要验证证书是否已正确安装,请运行:
mitmproxy --port 9000
此命令在端口 9000
上运行 mitmproxy。在另一个窗口中,运行:
curl --proxy "http://localhost:9000" "https://httpbin.org/status/200"
如果一切设置正确,信息将显示在 mitmproxy 窗口上,并且 curl 命令不会生成任何错误。
使用代理运行 Docker 守护进程
要使 Docker 通过代理连接,您必须使用适当的环境变量启动 Docker 守护进程。最简单的方法是关闭 Docker(例如sudo initctl stop docker
),然后手动运行 Docker。 以 root 身份运行:
export HTTP_PROXY="http://localhost:9000"
export HTTPS_PROXY="https://localhost:9000"
docker daemon --debug
此命令启动 Docker 守护进程并通过 mitmproxy 代理所有连接。
运行 Docker 客户端
现在我们已经运行了 mitmproxy 和 Docker,我们可以尝试登录并推送容器镜像。 您可能需要以 root 身份运行才能执行此操作。 例如:
docker login s3-testing.myregistry.com:5050
docker push s3-testing.myregistry.com:5050/root/docker-test/docker-image
在上面的示例中,我们在 mitmproxy 窗口上看到以下跟踪:
上图中显示了:
- 最初的 PUT 请求通过 201 状态代码正常运行。
- 201 将客户端重定向到 S3 存储桶。
- 对 AWS 存储桶的 HEAD 请求报告了 403 Unauthorized。
这强烈表明 S3 用户没有权利执行 HEAD 请求的权限。 解决办法:再次检查 IAM权限。 一旦设置了正确的权限,错误就会消失。
缺失 gitlab-registry.key
阻止容器镜像库删除
如果您禁用实例的 Container Registry 并尝试删除具有容器仓库的项目,则会发生以下错误:
Errno::ENOENT: No such file or directory @ rb_sysopen - /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key
在这种情况下,请按照下列步骤操作:
-
在
gitlab.rb
中临时启用 Container Registry 的实例范围设置:gitlab_rails['registry_enabled'] = true
- 保存文件并重新配置极狐GitLab 使更改生效。
- 再次尝试删除。
如果使用常用方法仍然无法移除仓库,可以使用 GitLab Rails 控制台强制移除项目:
# Path to the project you'd like to remove
prj = Project.find_by_full_path(<project_path>)
# The following will delete the project's container registry, so be sure to double-check the path beforehand!
if prj.has_container_registry_tags?
prj.container_repositories.each { |p| p.destroy }
end