프록시 뒤에서 GitLab Runner 실행하기

Tier: Free, Premium, Ultimate Offering: GitLab.com, Self-managed

이 가이드는 명시적으로 Docker executor를 사용하여 프록시 뒤에서 GitLab Runner를 작동시키는 데 목표를 두고 있습니다.

계속하기 전에, 이미 동일한 머신에 Docker를 설치하고 GitLab Runner를 설치했는지 확인하세요.

CNTLM 구성

note
이미 인증없이 프록시를 사용 중인 경우, 이 섹션은 선택 사항입니다. 도커 구성로 직접 건너뛸 수 있습니다. CNTLM 구성은 인증이 필요한 프록시 뒤에 있을 때만 필요하지만, 어떤 경우에도 사용하는 것이 권장됩니다.

CNTLM은 로컬 프록시로 사용할 수 있는 리눅스 프록시로서 프록시 세부 정보를 수동으로 추가하는 것과 비교하여 2가지 주요 장점이 있습니다:

  • 자격 증명을 변경해야 하는 한 곳
  • 도커 실행기에서 자격 증명을 액세스할 수 없음

CNTLM을 설치했다고 가정하고 시작하세요.

CNTLM이 docker0 인터페이스를 수신하도록 설정

추가 보안을 위해, 서버를 외부 환경으로부터 보호하기 위해 CNTLM을 docker0 인터페이스에서 수신하도록 바인딩할 수 있습니다. 해당 인터페이스의 IP는 컨테이너 내부에서 접근 가능합니다. CNTLM을 Docker 호스트에서 이 주소로만 바인딩하도록 지시하면 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 # 자신의 docker0 인터페이스 IP로 변경
    
  3. 변경 사항을 저장하고 서비스를 다시 시작합니다:

    sudo systemctl restart cntlm
    

이미지 다운로드를 위한 Docker 구성

note
다음은 systemd를 지원하는 OS에 적용됩니다.

프록시 사용 방법은 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 드롭인 디렉터리를 만듭니다:

    mkdir /etc/systemd/system/gitlab-runner.service.d
    
  2. HTTP_PROXY 환경 변수를 추가하는 /etc/systemd/system/gitlab-runner.service.d/http-proxy.conf라는 파일을 만듭니다:

    [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 컨테이너에 프록시 추가

러너를 등록한 후, 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 executor(dind)를 사용할 때, docker push가 차단되지 않도록 하려면 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://프록시:8080",
            "httpsProxy": "http://프록시:8080",
            "noProxy": "docker:2375,docker:2376"
        }
    }
}

또한, Docker executor의 컨테이너에 설정을 전달하려면, 컨테이너 내부에 $HOME/.docker/config.json도 만들어야 합니다. 이는 .gitlab-ci.ymlbefore_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"

참고: TOML 파일 내부에서 단일 문자열로 지정된 셸에서 JSON 파일을 생성하므로 여기에서는 "\" 추가 이스케이핑 수준이 필요합니다. 이것이 YAML이 아니기 때문에 :는 이스케이프하지 마십시오.

NO_PROXY 목록을 확장해야 하는 경우 와일드카드 *는 접미사에 대해서만 작동하며, 접두사나 CIDR 표기법에는 작동하지 않음을 주의하십시오. 자세한 정보는 다음을 참조하십시오. https://github.com/moby/moby/issues/9145 그리고 https://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 헤더가 있는지 확인합니다. RateLimit-ResetTime 헤더는 유효한 HTTP Date (RFC1123)인 값, 예를 들면 Wed, 21 Oct 2015 07:28:00 GMT을 가져야 합니다.
    • 헤더가 존재하고 유효한 값이 있는 경우, Runner는 지정된 시간까지 기다리고 다른 요청을 발행합니다.
    • 헤더가 존재하지만 올바른 날짜가 아닌 경우, 1분의 대체값이 사용됩니다.
    • 헤더가 없는 경우, 추가 조치를 취하지 않고 응답 오류가 반환됩니다.
  3. 위의 프로세스를 5회 반복한 후, 속도 제한으로 포기함 오류가 반환됩니다.

참고: 모든 헤더 키가 http.CanonicalHeaderKey 함수를 통과하므로 헤더 RateLimit-ResetTime은 대소문자 구분이 없습니다.