极狐GitLab 容器镜像库管理

使用极狐GitLab 容器镜像库,每个项目都可以拥有自己的空间来存储 Docker 镜像。

Docker 文档 中阅读有关 Docker Registry 的更多信息。

本文档是管理员指南。

启用容器镜像库

启用容器镜像库的过程取决于您使用的安装类型。

Linux 软件包安装

如果您使用 Linux 软件包安装极狐GitLab,则默认情况下容器镜像库可能可用,也可能不可用。

在以下情况下,容器镜像库会自动启用并在您的极狐GitLab 域名端口 5050 上可用:

否则,不可启用容器镜像库。要启用它:

容器镜像库默认在 HTTPS 下工作。 您可以使用 HTTP,但不推荐使用,并且超出了本文档的范围。 如果您想这样做,请阅读 insecure Registry 文档

自编译安装

如果您自编译您的极狐GitLab 安装:

  1. 您必须使用与您正在安装的极狐GitLab 版本对应的镜像部署 Registry
  2. 安装完成后,要启用它,必须在 gitlab.yml 中配置 Registry。
  3. 使用 lib/support/nginx/registry-ssl 下的示例 NGINX 配置文件,并编辑它以匹配 hostport 和 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 truefalse。在极狐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
caution如果没有设置 auth,用户可以在没有身份验证的情况下拉取 Docker 镜像。

容器镜像库域名配置

有两种方法可以配置镜像库的外部域名:

由于容器镜像库需要 TLS 证书,因此成本可能是一个考虑因素。

在首次配置容器镜像库之前,请考虑这一点。

使用现有的极狐GitLab 域名配置容器镜像库

如果镜像库配置为使用现有的极狐GitLab 域名,您可以在端口上公开镜像库。这样您就可以重用现有的极狐GitLab TLS 证书。

如果极狐GitLab 域是 https://gitlab.example.com 并且对外的端口是 5050

  • 使用 Linux 软件包安装时,在 gitlab.rb 中配置。
  • 使用自编译安装时,在 gitlab.yml 中配置。

确保您选择的端口与 Registry 侦听的端口不同(默认为 5000),否则会发生冲突。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 您的 /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"
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

  3. 验证使用:

    openssl s_client -showcerts -servername gitlab.example.com -connect gitlab.example.com:5050 > cacert.pem
    

如果您的证书提供商提供 CA Bundle 证书,请将它们附加到 TLS 证书文件。

:::TabTitle 自编译(源)

  1. 打开/home/git/gitlab/config/gitlab.yml,找到registry条目并进行以下配置:

    registry:
      enabled: true
      host: gitlab.example.com
      port: 5050
    
  2. 保存文件并重新启动极狐GitLab 以使更改生效。

  3. 在 NGINX 中进行相关更改(域名、端口、TLS 证书路径)。

::EndTabs

用户现在应该能够使用他们的极狐GitLab 凭据登录到容器镜像库:

docker login gitlab.example.com:5050

使用独立的域名配置容器镜像库

当 Registry 配置为使用自己的域名时,您需要该特定域名的 TLS 证书(例如,registry.example.com)。 如果托管在现有极狐GitLab 域名的子域名下,您可能需要通配符证书,例如,*.gitlab.example.com 是匹配 registry.gitlab.example.com 的通配符,与 *.example.com 不同。

除了手动生成的 SSL 证书(在此处说明),Let’s Encrypt 自动生成的证书也支持在 Linux软件包安装中使用

假设您希望容器镜像库可通过 https://registry.gitlab.example.com 访问。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 将您的 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.*
    
  2. 放置好 TLS 证书后,编辑 /etc/gitlab/gitlab.rb

    registry_external_url 'https://registry.gitlab.example.com'
    

    registry_external_url 正在侦听 HTTPS。

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

:::TabTitle 自编译(源)

  1. 打开/home/git/gitlab/config/gitlab.yml,找到registry条目并使用以下配置:

    registry:
      enabled: true
      host: registry.gitlab.example.com
    
  2. 保存文件并重新启动极狐GitLab 以使更改生效。
  3. 在 NGINX 中进行相关更改(域名、端口、TLS 证书路径)。

::EndTabs

用户现在应该能够使用他们的极狐GitLab 凭据登录到容器镜像库:

docker login registry.gitlab.example.com

在站点范围内禁用容器镜像库

当您按照这些步骤禁用镜像库时,您不会删除任何现有的 Docker 镜像。 这是由 Registry 应用程序本身处理的。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 打开 /etc/gitlab/gitlab.rb 并将 registry['enable'] 设置为 false

    registry['enable'] = false
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

  1. 打开/home/git/gitlab/config/gitlab.yml,找到registry条目并将enabled设置为false

    registry:
      enabled: false
    
  2. 保存文件并重新启动极狐GitLab 以使更改生效。

在站点中的新项目范围内禁用 Container Registry

如果容器镜像库已启用,则它应该可用于所有新项目。 要禁用此功能并让项目所有者自行启用容器镜像库,请按照以下步骤操作。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 编辑 /etc/gitlab/gitlab.rb 并添加以下内容:

    gitlab_rails['gitlab_default_projects_features_container_registry'] = false
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

  1. 打开/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
    
  2. 保存文件并重新启动极狐GitLab 以使更改生效。

::EndTabs

增加令牌期限

在极狐GitLab 中,容器镜像库的令牌每五分钟过期一次。 要增加令牌期限:

  1. 在左侧边栏中,选择 搜索或转到
  2. 选择 管理中心
  3. 在左侧边栏中,选择 设置 > CI/CD
  4. 展开 容器镜像库
  5. 对于 授权令牌期限(分钟),更新数值。
  6. 选择 保存更改

配置容器镜像库的存储

note对于支持它的存储后端,您可以使用对象版本控制来保留、检索和恢复存储在存储桶中的每个对象的非当前版本。但是,这可能会导致更高的存储使用率和成本。由于镜像库的运作方式,镜像上传后首先存储在临时路径中,然后传输到最终位置。对于对象存储后端,包括 S3 和 GCS,这种传输是通过先复制后删除来实现的。启用对象版本控制后,这些已删除的临时上传制品将保留为非当前版本,因此会增加存储桶大小。为确保在给定时间后删除非当前版本,您应该在您的存储提供商处,配置对象生命周期策略。
caution不要直接修改容器镜像库存储的文件或对象。除了镜像库写入或删除这些条目之外的任何操作,都可能导致实例范围内的数据一致性和不稳定问题,可能无法从中恢复。

您可以通过配置存储驱动程序来配置容器镜像库以使用各种存储后端。默认情况下极狐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 服务器用户都必须可以访问这个目录。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

Linux 软件包安装实例中,存储镜像的默认位置是 /var/opt/gitlab/gitlab-rails/shared/registry。要改变它,请参考以下步骤:

  1. 编辑 /etc/gitlab/gitlab.rb

    gitlab_rails['registry_path'] = "/path/to/registry/storage"
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

自编译安装实例中,镜像存储的默认位置是 /home/git/gitlab/shared/registry。要改变它,请参考以下步骤:

  1. 打开/home/git/gitlab/config/gitlab.yml,找到registry条目并更改path设置:

    registry:
      path: shared/registry
    
  2. 保存文件并 重新启动极狐GitLab 以使更改生效。

::EndTabs

使用对象存储

如果要将镜像存储在对象存储上,可以更改容器镜像库的存储驱动程序。

caution极狐GitLab 不备份未存储在文件系统上的 Docker 镜像。如果需要,可以通过对象存储提供商启用备份。

Linux 软件包安装

要在 Linux 软件包安装中配置 s3 存储驱动程序:

  1. 编辑 /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 角色 并省略 accesskeysecretkey。 确保您的 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/objectAWS S3 设置为 false

    您可以设置与 S3 的连接的速率限制,避免来自 S3 API 的 503 错误。请将 maxrequestspersecond 设置为 S3 请求速率阈值内的数字:

       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
       }
     }
    
  2. 保存文件并重新配置极狐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 应该是存在的存储桶的名称,并且不能包含子目录。

零停机迁移到对象存储

要在不停止容器镜像库的情况下迁移存储,请将容器镜像库设置为只读模式。在大型实例中,这可能需要容器镜像库处于只读模式一段时间。在此期间,您可以从容器镜像库中拉取,但无法推送。

  1. 可选:为了减少需要迁移的数据量,运行无停机垃圾收集工具
  2. 此示例使用 aws CLI。 如果您之前未配置 CLI,则必须通过运行 sudo aws configure 来配置您的凭据。由于非管理员用户可能无法访问容器镜像库文件夹,因此请确保使用 sudo。 要检查您的凭证配置,请运行 ls 以列出所有存储桶。

    sudo aws --endpoint-url https://your-object-storage-backend.com s3 ls
    

    如果您使用 AWS 作为后端,则不需要 --endpoint-url

  3. 将初始数据复制到您的 S3 存储桶,例如使用 aws CLI cpsync 命令。 确保将 docker 文件夹作为存储桶内的顶级文件夹。

    sudo aws --endpoint-url https://your-object-storage-backend.com s3 sync registry s3://mybucket
    
    note如果您有大量数据,您或许可以通过运行并行同步操作来提高性能。
  4. 要执行最终的数据同步,将容器镜像库置于只读模式,并重新配置极狐GitLab

  5. 将初始数据加载到 S3 存储桶后的任何更改同步,并删除目标存储桶中存在但源中不存在的文件:

    sudo aws --endpoint-url https://your-object-storage-backend.com s3 sync registry s3://mybucket --delete --dryrun
    

    验证命令按预期执行后,删除 --dryrun 标志并运行命令。

    caution--delete 标志删除目标中存在但源中不存在的文件。 如果交换源和目标,则镜像库中的所有数据都将被删除。
  6. 通过查看以下两个命令返回的文件计数,验证所有容器镜像仓库文件都已上传到对象存储:

    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 目录和子目录中的内容。

  7. 将您的镜像库配置为使用 S3 存储桶进行存储

  8. 为了使更改生效,将镜像库设置回 读写 模式并重新配置极狐GitLab

迁移到 Azure 对象存储

存储驱动的默认配置将于 16.0 版本变更。

caution存储驱动的默认配置将于 16.0 版本变更。存储驱动程序将使用 / 作为默认根目录。您现在可以将 trimlegacyrootprefix: false 添加到当前配置中以避免任何中断。

从现有文件系统或其他对象存储提供程序移动到 Azure 对象存储时,必须将镜像库配置为使用标准根目录。 此配置是通过在镜像库配置的 Azure 存储驱动程序部分中,设置 trimlegacyrootprefix: true 来完成的。 如果没有此配置,Azure 存储驱动程序将使用 // 而不是 / 作为根路径的第一部分,从而使迁移后的镜像无法访问。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

registry['storage'] = {
  'azure' => {
    'accountname' => 'accountname',
    'accountkey' => 'base64encodedaccountkey',
    'container' => 'containername',
    'rootdirectory' => '/azure/virtual/container',
    'trimlegacyrootprefix' => 'true'
  }
}

:::TabTitle 自编译(源)

storage:
  azure:
    accountname: accountname
    accountkey: base64encodedaccountkey
    container: containername
    rootdirectory: /azure/virtual/container
    trimlegacyrootprefix: true

::EndTabs

禁用存储驱动程序的重定向

默认情况下,访问配置有远程后端的镜像库的用户,被重定向到存储驱动程序的默认后端。例如,可以使用 s3 存储驱动程序配置镜像库,它将请求重定向到远程 S3 存储桶以减轻极狐GitLab 服务器上的负载。

但是,对于通常无法访问公共服务器的内部主机使用的镜像库,这种行为是不可取的。要禁用重定向和代理下载,请将 disable 标志设置为 true,如下所示。 这使得所有流量始终通过 Registry 服务。 这会提高安全性(减少表面攻击,因为存储后端不可公开访问),但性能更差(所有流量都通过服务重定向)。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 编辑 /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
       }
     }
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

  1. 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
    
  2. 保存文件并重新启动极狐GitLab 以使更改生效。

::EndTabs

加密的 S3 存储桶

您可以将 AWS KMS 服务器端加密用于默认启用 SSE-S3 或 SSE-KMS 加密的 S3 存储桶。 不支持客户主密钥 (CMK) 和 SSE-C 加密,因为这需要在每个请求中发送加密密钥。

对于 SSE-S3,您必须在镜像库设置中启用 encrypt 选项。 您如何执行此操作取决于您安装极狐GitLab 的方式。 按照此处与您的安装方法相匹配的说明进行操作。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 编辑 /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
       }
     }
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

  1. 编辑您的镜像库配置 YAML 文件:

     storage:
       s3:
         accesskey: 'AKIAKIAKI'
         secretkey: 'secret123'
         bucket: 'gitlab-registry-bucket-AKIAKIAKI'
         region: 'your-s3-region'
         regionendpoint: 'your-s3-regionendpoint'
         encrypt: true
    
  2. 保存文件并重新启动极狐GitLab 以使更改生效。

::EndTabs

存储限制

目前没有存储限制,这意味着用户可以上传无限数量的任意大小的 Docker 镜像。

更改镜像库的内部端口

默认情况下,Registry 服务器在端口 5000 上侦听本地主机,这是 Registry 服务器应接受连接的地址。 在下面的示例中,我们将 Registry 的端口设置为 5010

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 打开 /etc/gitlab/gitlab.rb 并设置 registry['registry_http_addr']

    registry['registry_http_addr'] = "localhost:5010"
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

  1. 打开 Registry 服务器的配置文件并编辑 http:addr 值:

    http:
      addr: localhost:5010
    
  2. 保存文件并重新启动 Registry 服务器。

::EndTabs

禁用某个项目的容器镜像库

如果在您的极狐GitLab 实例中启用了 Registry,但您的项目不需要它,您可以在项目的设置中禁用。

使用外部容器镜像库作为身份验证端点

对外部容器镜像库的支持废弃于 15.8 版本,并将删除于 16.0 版本。

如果您使用外部容器镜像库,则与容器镜像库关联的某些功能可能不可用,或具有固有风险。

要使集成工作,必须将外部镜像库配置为使用 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 :tagregistry.example.com/group/project/my/image-name:tag,并且只识别 registry.example.com/group/project:tag

Linux 软件包安装

您可以将极狐GitLab 用作具有外部容器镜像库的身份验证端点。

  1. 打开 /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 容器镜像库功能和身份验证端点。极狐云原生 ChartGitLab 捆绑的容器镜像库服务即使启用也不会启动。
    • gitlab_rails['registry_api_url'] = "http://<external_registry_host>:5000" 必须更改以匹配安装 Registry 的主机。如果外部镜像库配置为使用 TLS,它还必须指定 https。 阅读有关 Docker Registry 文档 的更多信息。

1.极狐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 a Linux package installation 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 指定的内容。 如果未指定文件,Linux 软件包安装会将其默认为 /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key 并填充它。

  1. 要更改极狐GitLab 容器镜像库页面中显示的容器镜像库 URL,请进行以下配置:

    gitlab_rails['registry_host'] = "registry.gitlab.example.com"
    gitlab_rails['registry_port'] = "5005"
    
  2. 保存文件并 重新配置极狐GitLab 以使更改生效。

自编译安装

  1. 打开/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
    

    阅读更多关于这些参数的含义。

  2. 保存文件并重新启动极狐GitLab 以使更改生效。

配置容器镜像库通知

您可以将容器镜像库配置为发送 Webhook 通知以响应镜像库中发生的事件。

Docker Registry 通知文档 中阅读有关容器镜像库通知配置选项的更多信息。

您可以为容器镜像库配置多个端点。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

要在 Linux 软件包中配置通知端点:

  1. 编辑 /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"]
        }
      }
    ]
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

配置通知端点是在您部署 Docker Registry 时创建的镜像库中配置的 YAML 文件中完成的。

示例:

notifications:
  endpoints:
    - name: alistener
      disabled: false
      url: https://my.listener.com/event
      headers: <http.Header>
      timeout: 500
      threshold: 5
      backoff: 1000

::EndTabs

立即运行清理策略

caution如果您使用分布式架构并且 Sidekiq 在不同的节点上运行,则清理策略不起作用。要解决此问题,您必须在 Sidekiq 节点上配置 gitlab.rb 文件以指向正确的仓库 URL,并将 registry.key 文件复制到每个 Sidekiq 节点。

为了减少给定项目使用的容器镜像库磁盘空间,管理员可以清理镜像标签和运行垃圾收集

按项目列出 Registry 磁盘空间使用情况

要查找每个项目使用的磁盘空间,请在 Rails 控制台中运行以下命令:

projects_and_size = [["project_id", "creator_id", "registry_size_bytes", "project path"]]
# You need to specify the projects that you want to look through. You can get these in any manner.
projects = Project.last(100)

projects.each do |p|
   project_total_size = 0
   container_repositories = p.container_repositories

   container_repositories.each do |c|
       c.tags.each do |t|
          project_total_size = project_total_size + t.total_size unless t.total_size.nil?
       end
   end

   if project_total_size > 0
      projects_and_size << [p.project_id, p.creator.id, project_total_size, p.full_path]
   end
end

# print it as comma separated output
projects_and_size.each do |ps|
   puts "%s,%s,%s,%s" % ps
end

要通过运行清理策略删除镜像标签,请在 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(container_repository: repo, current_user: user, params: policy.attributes.except("created_at", "updated_at")).execute
end

您还可以按计划运行清理。

容器镜像库垃圾回收

note您的对象存储提供商(例如 Amazon S3 Lifecycle)中的保留策略可能会阻止对象被正确删除。

容器镜像库可能会使用大量存储空间,您可能希望减少存储使用。 在列出的选项中,删除标签是最有效的选项。然而,单独删除标签并不会删除镜像层,它只会使底层镜像清单保持未打标签状态。

为了更有效地释放空间,容器镜像库有一个垃圾收集器,可以删除未引用的层和(可选)未打标签的清单。

要启动垃圾收集器,请使用 gitlab-ctl 提供的 registry-garbage-collect 命令。

caution此命令会在垃圾收集之前关闭容器镜像库,并仅在垃圾收集完成后再次启动。如果您希望避免停机,可以手动将容器镜像库设置为只读模式并绕过 gitlab-ctl

执行垃圾收集所需的时间与容器镜像库数据大小成正比。

先决条件:

了解内容可寻址层

考虑以下示例,您首先在其中构建镜像:

# 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 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

要启用只读模式:

  1. /etc/gitlab/gitlab.rb 中,指定只读模式:

      registry['storage'] = {
        'filesystem' => {
          'rootdirectory' => "<your_registry_storage_path>"
        },
        'maintenance' => {
          'readonly' => {
            'enabled' => true
          }
        }
      }
    
  2. 保存并重新配置极狐GitLab:

    sudo gitlab-ctl reconfigure
    

    此命令将容器镜像库设置为只读模式。

  3. 接下来,触发垃圾收集命令之一:

    # Remove unreferenced layers
    sudo /opt/gitlab/embedded/bin/registry garbage-collect /var/opt/gitlab/registry/config.yml
    
    # Remove untagged manifests and unreferenced layers
    sudo /opt/gitlab/embedded/bin/registry garbage-collect -m /var/opt/gitlab/registry/config.yml
    

    此命令启动垃圾收集,完成时间与镜像库数据大小成正比。

  4. 完成后,在/etc/gitlab/gitlab.rb 中将其改回读写模式:

     registry['storage'] = {
       'filesystem' => {
         'rootdirectory' => "<your_registry_storage_path>"
       },
       'maintenance' => {
         'readonly' => {
           'enabled' => false
         }
       }
     }
    
  5. 保存并重启配置极狐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 在不同的节点上运行(Linux 软件包安装)

默认情况下,软件包假定两个服务都在同一节点上运行。为了让极狐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)上公开它。

GitLab Registry diagram

上图描述的流程:

  1. 用户在他们的客户端上运行 docker login registry.gitlab.example。通过端口 443 到达 Web 服务器(或 LB)。
  2. Web 服务器连接到 Registry 后端池(默认使用端口 5000)。由于用户没有提供有效的令牌,Registry 返回 401 HTTP 代码和 URL(来自 Registry 配置的 token_realm)从哪里获取。这指向极狐GitLab API。
  3. Docker 客户端然后连接到极狐GitLab API 并获取令牌。
  4. API 使用 registry key对令牌进行签名,并将其交给 Docker 客户端。
  5. 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 对话以处理镜像删除。

故障排查

在深入研究以下部分之前,查看一些基本的故障排除信息:

  1. 检查以确保 Docker 客户端和极狐GitLab 服务器上的系统时钟已同步(例如通过 NTP)。

  2. 如果您使用的是 S3 支持的镜像库,请仔细检查 IAM 权限和 S3 凭证(包括区域)是否正确。有关更多详细信息,请参阅示例 IAM 策略

  3. 检查镜像库日志(例如/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 对是匹配的:

/opt/gitlab/embedded/bin/openssl x509 -noout -modulus -in /var/opt/gitlab/registry/gitlab-registry.crt | /opt/gitlab/embedded/bin/openssl sha256
/opt/gitlab/embedded/bin/openssl rsa -noout -modulus -in /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key | /opt/gitlab/embedded/bin/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) 之间的值开始。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 编辑 /etc/gitlab/gitlab.rb

    registry['storage'] = {
      's3' => {
        'accesskey' => 'AKIAKIAKI',
        'secretkey' => 'secret123',
        'bucket'    => 'gitlab-registry-bucket-AKIAKIAKI',
        'chunksize' => 25000000
      }
    }
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

  1. 编辑 config/gitlab.yml

    storage:
      s3:
        accesskey: 'AKIAKIAKI'
        secretkey: 'secret123'
        bucket: 'gitlab-registry-bucket-AKIAKIAKI'
        chunksize: 25000000
    
  2. 保存文件并重新启动极狐GitLab 以使更改生效。

::EndTabs

支持较旧的 Docker 客户端

极狐GitLab 附带的 Docker 容器镜像库默认禁用 schema1 manifest。如果您仍在使用较旧的 Docker 客户端(1.9 或更早版本),您可能会在推送镜像时遇到错误。

您可以添加配置选项以实现向后兼容性。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 编辑 /etc/gitlab/gitlab.rb

    registry['compatibility_schema1_enabled'] = true
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 编辑您在部署镜像库 时创建的 YAML 配置文件。 添加以下代码段:

    compatibility:
        schema1:
            enabled: true
    
  2. 重新启动镜像库以使更改生效。

::EndTabs

Docker 连接错误

当群组、项目或分支名称中存在特殊字符时,可能会发生 Docker 连接错误。特殊字符包括:

  • 前置下划线
  • 后置连字符/破折号
  • 双连字符/破折号

要解决此问题,您可以更改群组路径、更改项目路径或更改分支名称。另一种选择是创建推送规则,在实例级别防止这种情况。

镜像推送错误

docker login 工作正常时,尝试推送镜像出现错误或 “retrying” 循环,NGINX 转发到镜像库的 header 可能存在问题。默认推荐的 NGINX 配置应该可以解决这个问题,但它可能发生在 SSL 被卸载到第三方反向代理的自定义设置中。

一个简单的解决方案是在镜像库中启用相对 URL。

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  1. 编辑 /etc/gitlab/gitlab.rb

    registry['env'] = {
      "REGISTRY_HTTP_RELATIVEURLS" => true
    }
    
  2. 保存文件并重新配置极狐GitLab 以使更改生效。

:::TabTitle 自编译(源)

  1. 编辑您在部署镜像库时创建的 YAML 配置文件。 添加以下代码段:

    http:
        relativeurls: true
    
  2. 保存文件并重新启动极狐GitLab 以使更改生效。

::EndTabs

启用 Registry debug 服务器

您可以使用容器镜像库调试服务器来诊断问题。调试端点可以监控指标和运行状况,以及进行分析。

caution可以从调试端点获得敏感信息。在生产环境中必须锁定对调试端点的访问。

可以通过在 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:

  1. 安装 mitmproxy
  2. 运行 mitmproxy --port 9000 来生成它的证书。输入 CTRL-C 退出。
  3. ~/.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 窗口上看到以下跟踪:

mitmproxy output from Docker

上图中显示了:

  • 最初的 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

在这种情况下,请按照下列步骤操作:

  1. gitlab.rb 中临时启用 Container Registry 的实例范围设置:

    gitlab_rails['registry_enabled'] = true
    
  2. 保存文件并重新配置极狐GitLab 使更改生效。
  3. 再次尝试删除。

如果使用常用方法仍然无法移除仓库,可以使用极狐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