- 先决条件
- 为群组启用或关闭 Dependency Proxy
- 查看 Dependency Proxy
- 对 Docker 镜像使用 Dependency Proxy
- 减少存储使用
- Docker Hub 速率限制和 Dependency Proxy
- 故障排查
Dependency Proxy
GitLab Dependency Proxy 是一个本地代理,可用于您经常访问的上游镜像。
在 CI/CD 的情况下,Dependency Proxy 接收请求并从镜像库返回上游镜像,作为 pull-through cache。
先决条件
- Dependency Proxy 默认启用,但可以由管理员关闭。
为群组启用或关闭 Dependency Proxy
要为群组启用或关闭 Dependency Proxy:
- 在顶部栏上,选择 主菜单 > 群组 并找到您的群组。
- 在左侧边栏上,选择 设置 > 软件包与镜像库。
- 展开 依赖代理 部分。
- 要启用代理,请打开 启用代理。要关闭它,请关闭切换开关。
此设置仅影响群组的依赖代理。只有管理员可以为整个实例打开或关闭依赖代理。
查看 Dependency Proxy
查看 Dependency Proxy:
- 在顶部栏上,选择 主菜单 > 群组 并找到您的群组。
- 在左侧边栏上,选择 软件包与镜像库 > 依赖项代理。
Dependency Proxy 不适用于项目。
对 Docker 镜像使用 Dependency Proxy
您可以使用 GitLab 作为 Docker 镜像的来源。
先决条件:
- 您的镜像必须存储在 Docker Hub 上。
使用 Dependency Proxy 进行身份验证
- 引入于 13.7 版本,功能标志名为
dependency_proxy_for_private_groups
。默认启用。- 功能标志
dependency_proxy_for_private_groups
移除于 15.0 版本。
由于 Dependency Proxy 将 Docker 镜像存储在与您的群组关联的空间中,因此您必须针对 Dependency Proxy 进行身份验证。
按照 使用来自私有注册表的图像的说明,而不使用 registry.example.com:5000
,需使用没有端口 gitlab.example.com
的 GitLab 域名。
例如,手动登录:
docker login gitlab.example.com --username my_username --password my_password
您可以使用以下方法进行身份验证:
- 您的 GitLab 用户名和密码。
-
个人访问令牌,范围设置为
read_registry
和write_registry
。 - 群组部署令牌,范围设置为
read_registry
和write_registry
。
使用个人访问令牌或用户名和密码访问 Dependency Proxy 的用户,至少需要从中提取镜像的群组的 Guest 成员权限。
依赖代理遵循 Docker v2 令牌身份验证流程,向客户端发出 JWT 以用于拉取请求。由于身份验证而发布的 JWT 会在一段时间后过期。当令牌过期时,大多数 Docker 客户端会存储您的凭据并自动请求新令牌而无需进一步操作。
SAML SSO
启用 SSO enforcement 后,用户必须先通过 SSO 登录,然后才能通过 Dependency Proxy 拉取镜像。
在 CI/CD 内进行身份验证
Runners 会自动登录 Dependency Proxy。要通过 Dependency Proxy 拉取,请使用预定义变量 之一:
-
CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
通过顶级群组拉取。 -
CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX
通过项目所在的子组或直接群组拉取。
拉取最新的 alpine 镜像的示例:
# .gitlab-ci.yml
image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/alpine:latest
您还可以使用其他额外的预定义 CI/CD 变量:
-
CI_DEPENDENCY_PROXY_USER
:用于登录 Dependency Proxy 的 CI/CD 用户。 -
CI_DEPENDENCY_PROXY_PASSWORD
:用于登录 Dependency Proxy 的 CI/CD 密码。 -
CI_DEPENDENCY_PROXY_SERVER
:用于登录 Dependency Proxy 的服务器。 -
CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
:用于通过 Dependency Proxy 从顶级群组拉取镜像的镜像前缀。 -
CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX
:用于通过 Dependency Proxy 从项目所属的直接组或子组中拉取镜像的镜像前缀。
CI_DEPENDENCY_PROXY_SERVER
、CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
和 CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX
包括服务器端口。如果您明确包含 Dependency Proxy 路径,则必须包含端口,除非您已手动登录 Dependency Proxy 而不包含端口:
docker pull gitlab.example.com:443/my-group/dependency_proxy/containers/alpine:latest
使用 Dependency Proxy 构建镜像时的示例:
# Dockerfile
FROM gitlab.example.com:443/my-group/dependency_proxy/containers/alpine:latest
# .gitlab-ci.yml
image: docker:19.03.12
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
services:
- docker:19.03.12-dind
build:
image: docker:19.03.12
before_script:
- docker login -u $CI_DEPENDENCY_PROXY_USER -p $CI_DEPENDENCY_PROXY_PASSWORD $CI_DEPENDENCY_PROXY_SERVER
script:
- docker build -t test .
您还可以使用自定义 CI/CD 变量来存储和访问您的个人访问令牌或部署令牌。
在 Dependency Proxy 缓存中存储 Docker 镜像
要将 Docker 镜像存储在 Dependency Proxy 存储中:
- 在顶部栏上,选择 主菜单 > 群组 并找到您的群组。
- 在左侧边栏上,选择 软件包与镜像库 > 依赖项代理。
- 复制 依赖代理镜像前缀。
- 使用以下命令之一。在这些示例中,镜像是
alpine:latest
。 -
您还可以通过 digest 拉取镜像,以准确指定要拉取的镜像版本。
-
通过将镜像添加到您的
.gitlab-ci.yml
文件中,按标签拉取镜像:image: gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
-
通过将镜像添加到
.gitlab-ci.yml
文件中,通过 digest 提取镜像:image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/alpine@sha256:c9375e662992791e3f39e919b26f510e5254b42792519c180aad254e6b38f4dc
-
手动拉取 Docker 镜像:
docker pull gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
-
将 URL 添加到
Dockerfile
:FROM gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
-
极狐GitLab 从 Docker Hub 拉取 Docker 镜像并将 blob 缓存在 GitLab 服务器上。下次拉取同一个镜像时,GitLab 会从 Docker Hub 获取有关该镜像的最新信息,但会从 GitLab 服务器提供现有的 blob。
减少存储使用
有关减少 Dependency Proxy 上的存储使用的信息,请参阅减少 Dependency Proxy 存储使用。
Docker Hub 速率限制和 Dependency Proxy
2020 年 11 月,Docker 引入了来自 Docker Hub 的拉取请求的速率限制。 如果您的 GitLab CI/CD 配置 使用来自 Docker Hub 的镜像,则每次作业运行时,它都可以算作拉取请求。 为帮助解决此限制,您可以改为从 Dependency Proxy 缓存中拉取镜像。
当您拉取一个镜像时(通过使用类似 docker pull
的命令,或者在 .gitlab-ci.yml
文件中,image: foo:latest
),Docker 客户端会生成一个请求集合:
- 请求镜像 manifest。Manifest 包含有关如何构建镜像的信息。
- 使用 manifest,Docker 客户端一次请求一个层集合,也称为 blob。
Docker Hub 速率限制基于清单的 GET 请求数。 Dependency Proxy 会缓存给定图像的清单和 blob,因此当您再次请求时,不必联系 Docker Hub。
系统如何知道缓存的标签镜像是否过期?
如果您使用像 alpine:latest
这样的镜像标签,镜像会随着时间而改变。每次更改时,Manifest 都包含有关要请求哪些 blob 的不同信息。每次 manifest 更改时,Dependency Proxy 都不会拉取新镜像;它仅在 manifest 变得陈旧时进行检查。
Docker 不会将镜像 manifest 的 HEAD 请求计入速率限制。
您可以为 alpine:latest
发出 HEAD 请求,查看标头中返回的 digest(校验和)值,并确定 manifest 是否已更改。
Dependency Proxy 以 HEAD 请求启动所有请求。如果 manifest 已经过时,则只有这样才能拉取新镜像。
例如,如果您的流水线每五分钟拉取一次 node:latest
,Dependency Proxy 会缓存整个镜像,并且仅在 node:latest
更改时才更新它。因此,不需要在 6 小时内对镜像发出 360 个请求(超过 Docker Hub 速率限制),而是只有一个拉取请求,除非 manifest 在那段时间内发生了变化。
检查您的 Docker Hub 速率限制
如果您想知道您向 Docker Hub 发出了多少请求以及还有多少请求,您可以从 runner 运行这些命令,甚至可以在 CI/CD 脚本中运行:
# Note, you must have jq installed to run this command
TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq --raw-output .token) && curl --head --header "Authorization: Bearer $TOKEN" "https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest" 2>&1 | grep --ignore-case RateLimit
...
输出类似于:
RateLimit-Limit: 100;w=21600
RateLimit-Remaining: 98;w=21600
此示例显示了 6 小时内 100 次拉取的总限制,剩余 98 次拉取。
检查 CI/CD 作业中的速率限制
此示例显示了一个 GitLab CI/CD 作业,该作业使用安装了 jq
和 curl
的镜像:
hub_docker_quota_check:
stage: build
image: alpine:latest
tags:
- <optional_runner_tag>
before_script: apk add curl jq
script:
- |
TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq --raw-output .token) && curl --head --header "Authorization: Bearer $TOKEN" "https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest" 2>&1
故障排查
Dependency Proxy 连接失败
如果没有设置服务别名,docker:19.03.12
镜像将无法找到 dind
服务,并抛出如下错误:
error during connect: Get http://docker:2376/v1.39/info: dial tcp: lookup docker on 192.168.0.1:53: no such host
可以通过为 Docker 服务设置服务别名来解决:
services:
- name: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/docker:18.09.7-dind
alias: docker
从 CI/CD 作业向 Dependency Proxy 进行身份验证时的问题
极狐GitLab Runner 将自动向依赖代理进行身份验证。但是,底层的 Docker 引擎仍然受制于其授权解析过程。
身份验证机制中的错误配置可能会导致 HTTP Basic: Access denied
和 403: Access forbidden
错误。
您可以使用作业日志查看用于针对 Dependency Proxy 进行身份验证的身份验证机制:
Authenticating with credentials from $DOCKER_AUTH_CONFIG
Authenticating with credentials from /root/.docker/config.json
Authenticating with credentials from job payload (GitLab Registry)
确保您使用的是预期的身份验证机制。
拉取镜像时出现 “Not Found” 或 404 错误
类似于以下内容的 Docker 错误可能表明,运行构建作业的用户在指定的 Dependency Proxy 组中没有最低所需的 Guest 角色:
-
ERROR: gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest: not found failed to solve with frontend dockerfile.v0: failed to create LLB definition: gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest: not found
-
ERROR: Job failed: failed to pull image "gitlab.example.com:443/group1/dependency_proxy/containers/alpine:latest" with specified policies [always]: Error response from daemon: error parsing HTTP 404 response body: unexpected end of JSON input: "" (manager.go:237:1s)