使用代理运行极狐GitLab Runner

这个指南的目的是让带有 Docker 执行器的极狐GitLab Runner 通过代理工作。

开始前请确保您已经在同一台机器上安装了 Docker极狐GitLab Runner

配置 CNTLM

note 如果您已经使用了没有认证的代理,那么这个部分可选,并且您可以直接跳到配置 Docker部分。 只有当您使用经过认证的代理,您才需要配置 CNTLM。 但是无论在哪种情况下都推荐您配置 CNTLM。

CNTLM 是一个 Linux 代理,可以用作本地代理,并且与手动到处添加代理详情相比,有两个主要的优势:

  • 只有一个需要更改证书的来源。
  • 从 Docker Runner 无法访问证书。

假设您已经安装了 CNTLM, 您需要首先对其进行配置。

使 CNTLM 侦听 docker0 接口

为了额外的安全并且保护服务器不受外部影响,您可以绑定 CNTLM,使其在 docker0 接口上侦听,这个接口拥有从容器内部可以访问的 IP。 如果您让 Docker 主机上的 CNTLM 仅绑定到这个地址,Docker 容器就能够进行访问,但是外部则无法访问。

  1. 找到 Docker 使用的 IP:

    ip -4 -oneline addr show dev docker0
    

    一般是 172.17.0.1,我们将它称为 docker0_interface_ip

  2. 打开 CNTLM (/etc/cntlm.conf) 的配置文件。输入您的用户名、密码、域和代理主机,并配置您从上一步骤中获取到的 Listen IP 地址。 应如下所示:

    Username     testuser
    Domain       corp-uk
    Password     password
    Proxy        10.0.0.41:8080
    Proxy        10.0.0.42:8080
    Listen       172.17.0.1:3128 # Change to your docker0 interface IP
    
  3. 保存更改并重启服务:

    sudo systemctl restart cntlm
    

为下载镜像配置 Docker

note 以下适用于带有 systemd 支持的 OSes。

根据 Docker 文档中的指示了解如何使用代理。

服务文件应如下所示:

[Service]
Environment="HTTP_PROXY=http://docker0_interface_ip:3128/"
Environment="HTTPS_PROXY=http://docker0_interface_ip:3128/"

向极狐GitLab Runner 配置中添加代理变量

代理变量同样也需要添加到极狐GitLab Runner 配置中,这样它才能够获取使用代理的极狐GitLab 所分配的构建。

基本和上面所述的向 Docker 服务添加代理一样:

  1. gitlab-runner 服务创建 systemd drop-in 目录:

    mkdir /etc/systemd/system/gitlab-runner.service.d
    
  2. 创建名为 /etc/systemd/system/gitlab-runner.service.d/http-proxy.conf 的文件,该文件添加 HTTP_PROXY 环境变量:

    [Service]
    Environment="HTTP_PROXY=http://docker0_interface_ip:3128/"
    Environment="HTTPS_PROXY=http://docker0_interface_ip:3128/"
    
  3. 保存文件并刷新更改:

    systemctl daemon-reload
    
  4. 重启极狐GitLab Runner:

    sudo systemctl restart gitlab-runner
    
  5. 验证配置已加载:

    systemctl show --property=Environment gitlab-runner
    

    您应该能看到:

    Environment=HTTP_PROXY=http://docker0_interface_ip:3128/ HTTPS_PROXY=http://docker0_interface_ip:3128/
    

向 Docker 容器中添加代理

您在注册 Runner 后,您或许会想将您的代理设置传播到 Docker 容器(例如,git clone)。

为此,您需要编辑 /etc/gitlab-runner/config.toml 并向 [[runners]] 部分添加以下内容:

pre_get_sources_script = "git config --global http.proxy $HTTP_PROXY; git config --global https.proxy $HTTPS_PROXY"
environment = ["https_proxy=http://docker0_interface_ip:3128", "http_proxy=http://docker0_interface_ip:3128", "HTTPS_PROXY=docker0_interface_ip:3128", "HTTP_PROXY=docker0_interface_ip:3128"]

其中 docker0_interface_ipdocker0 接口的 IP 地址。

note 在我们的例子中,我们设置了大写和小写的变量,因为特定程序需要 HTTP_PROXY ,而其他则需要 http_proxy。 但是这些环境变量却没有统一的标准

使用 dind 服务时的代理设置

当使用 Docker-in-Docker 执行器 (dind) 时,或许有必要在 NO_PROXY 环境变量中指定 docker:2375,docker:2376。端口是必须的,否则会禁用 docker push

dind 的 dockerd 和本地 docker 客户端(https://hub.docker.com/_/docker/ 中所描述的) 之间的通信使用根的 Docker 配置中的代理变量。

为进行此配置,您需要编辑 /root/.docker/config.json,包含完整的代理配置,例如:

{
    "proxies": {
        "default": {
            "httpProxy": "http://proxy:8080",
            "httpsProxy": "http://proxy:8080",
            "noProxy": "docker:2375,docker:2376"
        }
    }
}

为将设置传递到 Docker 执行器的容器中,您还需要在容器中创建 $HOME/.docker/config.json。它可能会被创建为 .gitlab-ci.yml 中的 before_script 脚本,例如:

before_script:
  - mkdir -p $HOME/.docker/
  - 'echo "{ \"proxies\": { \"default\": { \"httpProxy\": \"$HTTP_PROXY\", \"httpsProxy\": \"$HTTPS_PROXY\", \"noProxy\": \"$NO_PROXY\" } } }" > $HOME/.docker/config.json'

或者在被影响的 gitlab-runner (/etc/gitlab-runner/config.toml)的配置中:

[[runners]]
  pre_build_script = "mkdir -p $HOME/.docker/ && echo \"{ \\\"proxies\\\": { \\\"default\\\": { \\\"httpProxy\\\": \\\"$HTTP_PROXY\\\", \\\"httpsProxy\\\": \\\"$HTTPS_PROXY\\\", \\\"noProxy\\\": \\\"$NO_PROXY\\\" } } }\" > $HOME/.docker/config.json"
note 还需要转义 " 的额外级别,因为创建了带有 Shell 的 JSON 文件,这个 Shell 被指定为 TOML 文件内的单个字符串。 因为它不是 YAML,所以不要转义 :

请注意,如果需要扩展 NO_PROXY 列表,通配符 * 仅对后缀生效,对前缀或 CIDR 标注都无效。 详情请参见 https://github.com/moby/moby/issues/9145https://unix.stackexchange.com/questions/23452/set-a-network-range-in-the-no-proxy-environment-variable

处理速率限制请求

极狐GitLab 实例或许会通过反向代理进行使用,这些反向代理对 API 请求有速率限制,以防滥用。极狐GitLab Runner 向 API 发送多个请求并可以检查这些速率限制。

因此,极狐GitLab Runner 用以下逻辑处理速率限制场景:

  1. 收到 429 - TooManyRequests 的响应码。
  2. RateLimit-ResetTime Header 检查响应 Header。RateLimit-ResetTime Header 应该有一个值,并且是有效的 HTTP Date (RFC1123),例如 Wed, 21 Oct 2015 07:28:00 GMT
    • 如果 Header 存在且是一个有效的值,Runner 会等到特定时间并发送另一个请求。
    • 如果 Header 存在,但不是一个有效的日期,会使用 1 分钟的回退。
    • 如果 Header 不存在,不会采取额外动作,且会返回响应错误。
  3. 上述过程重复 5 次,会返回 gave up due to rate limit 错误。
note RateLimit-ResetTime 区分大小写,因为所有的 Header Key 都要通过 http.CanonicalHeaderKey 功能运行。