종속성 프록시

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

GitLab 종속성 프록시는 자주 액세스하는 업스트림 이미지를 위한 로컬 프록시입니다.

CI/CD의 경우, 종속성 프록시는 요청을 수신하고 레지스트리에서 업스트림 이미지를 반환하며, 풀 스루 캐시 역할을 합니다.

전제 조건

종속성 프록시를 사용하려면 GitLab 인스턴스에서 활성화되어 있어야 합니다. 기본적으로 활성화되어 있지만, 관리자가 끌 수 있습니다.

지원되는 이미지 및 패키지

다음 이미지 및 패키지가 지원됩니다.

이미지/패키지 GitLab 버전
Docker 14.0+

계획된 추가 목록은 방향 페이지를 확인하세요.

그룹에 대한 종속성 프록시 활성화 또는 끄기

  • 필요 역할 변경됨: GitLab 15.0에서 Developer에서 Maintainer로.
  • 필요 역할 변경됨: GitLab 17.0에서 Maintainer에서 Owner로.

그룹에 대한 종속성 프록시를 활성화하거나 끄려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 그룹을 찾습니다.
  2. 설정 > 패키지 및 레지스트리를 선택합니다.
  3. 종속성 프록시 섹션을 확장합니다.
  4. 프록시를 활성화하려면 프록시 활성화를 켭니다. 끄려면 토글을 끕니다.

이 설정은 그룹에 대한 종속성 프록시만 영향을 미칩니다. 전체 GitLab 인스턴스에 대해 종속성 프록시를 켜거나 끌 수 있는 사람은 관리자뿐입니다.

종속성 프록시 보기

종속성 프록시를 보려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 그룹을 찾습니다.
  2. 작업 > 종속성 프록시를 선택합니다.

종속성 프록시는 프로젝트에서 사용할 수 없습니다.

Docker 이미지에 대한 종속성 프록시 사용

Docker 이미지를 위한 소스로 GitLab을 사용할 수 있습니다.

전제 조건:

  • 이미지가 Docker Hub에 저장되어 있어야 합니다.

종속성 프록시로 인증하기

  • GitLab 15.0에서 기능 플래그 dependency_proxy_for_private_groups제거됨.
  • 그룹 액세스 토큰에 대한 지원은 GitLab 16.3에 도입됨.

종속성 프록시는 그룹과 관련된 공간에 Docker 이미지를 저장하므로, 종속성 프록시에 대해 인증해야 합니다.

개인 레지스트리로부터 이미지를 사용하는 방법에 대한 지침을 따르되, registry.example.com:5000 대신 포트 없이 GitLab 도메인 gitlab.example.com을 사용합니다.

참고:
관리자 모드는 종속성 프록시 인증 중에 적용되지 않습니다. 관리자 모드가 활성화된 관리자이고 admin_mode 범위가 없는 개인 액세스 토큰을 생성하면, 해당 토큰은 관리자 모드가 활성화되었음에도 불구하고 작동합니다.

예를 들어, 수동으로 로그인하려면:

echo "$CONTAINER_REGISTRY_PASSWORD" | docker login gitlab.example.com --username my_username --password-stdin

다음 방법으로 인증할 수 있습니다:

개인 액세스 토큰이나 사용자 이름 및 비밀번호로 종속성 프록시에 액세스하는 사용자는 이미지를 가져오는 그룹에서 최소한 게스트 역할을 가져야 합니다.

종속성 프록시는 Docker v2 토큰 인증 흐름을 따르며, 클라이언트에 대한 JWT를 발급하여 풀 요청에 사용하도록 합니다. 인증 결과로 발급된 JWT는 일정 시간이 지나면 만료됩니다. 토큰이 만료되면 대부분의 Docker 클라이언트는 자격 증명을 저장하고 추가 작업 없이 자동으로 새 토큰을 요청합니다.

토큰 만료 시간은 구성 가능한 설정입니다. GitLab.com에서는 만료 시간이 15분입니다.

SAML SSO

SSO enforcement가 활성화되면, 사용자는 Dependency Proxy를 통해 이미지를 가져오기 전에 SSO를 통해 로그인해야 합니다.

SSO enforcement는 자동 병합에도 영향을 미칩니다. SSO 세션이 자동 병합이 트리거되기 전에 만료되면, 병합 파이프라인은 Dependency Proxy를 통해 이미지를 가져오는 데 실패합니다.

CI/CD 내에서 인증

러너는 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:20.10.16

variables:
  DOCKER_HOST: tcp://docker:2375
  DOCKER_TLS_CERTDIR: ""

services:
  - docker:20.10.16-dind

build:
  image: docker:20.10.16
  before_script:
    - echo "$CI_DEPENDENCY_PROXY_PASSWORD" | docker login $CI_DEPENDENCY_PROXY_SERVER -u $CI_DEPENDENCY_PROXY_USER --password-stdin
  script:
    - docker build -t test .

사용자 지정 CI/CD 변수를 사용하여 개인 액세스 토큰 또는 배포 토큰을 저장하고 접근할 수 있습니다.

Dependency Proxy 캐시에 Docker 이미지 저장

Dependency Proxy 저장소에 Docker 이미지를 저장하려면:

  1. 왼쪽 사이드바에서 Search or go to를 선택하고 그룹을 찾습니다.
  2. Operate > Dependency Proxy를 선택합니다.
  3. Dependency Proxy 이미지 접두사를 복사합니다.
  4. 이러한 명령 중 하나를 사용합니다. 이 예시에서는 이미지가 alpine:latest입니다.
  5. 특정 이미지 버전을 지정하기 위해 다이제스트로 이미지를 가져올 수 있습니다.

    • 태그로 이미지를 가져오려면 이미지를 .gitlab-ci.yml 파일에 추가합니다:

      image: gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
      
    • 다이제스트로 이미지를 가져오려면 이미지를 .gitlab-ci.yml 파일에 추가합니다:

      image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/alpine@sha256:c9375e662992791e3f39e919b26f510e5254b42792519c180aad254e6b38f4dc
      
    • Docker 이미지를 수동으로 가져옵니다:

      docker pull gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
      
    • Dockerfile에 URL을 추가합니다:

      FROM gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
      

GitLab은 Docker Hub에서 Docker 이미지를 가져와 GitLab 서버에 블롭을 캐시합니다. 다음에 동일한 이미지를 가져올 때 GitLab은 Docker Hub에서 이미지에 대한 최신 정보를 가져오지만, GitLab 서버에서 기존 블롭을 제공합니다.

저장소 사용량 줄이기

Dependency Proxy에서 저장소 사용량을 줄이는 정보는 Dependency Proxy 저장소 사용량 줄이기를 참조하세요.

Docker Hub 속도 제한 및 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 클라이언트는 여러 요청을 수행합니다:

  1. 이미지 매니페스트가 요청됩니다. 매니페스트는 이미지를 빌드하는 방법에 대한 정보를 포함합니다.

  2. 매니페스트를 사용하여 Docker 클라이언트는 하나씩 레이어(블롭이라고도 함)의 집합을 요청합니다.

Docker Hub 속도 제한은 매니페스트에 대한 GET 요청의 수를 기준으로 합니다. Dependency Proxy는 특정 이미지에 대해 매니페스트와 블롭을 캐시하므로, 다시 요청할 때 Docker Hub에 연락할 필요가 없습니다.

GitLab은 캐시된 태그가 붙은 이미지가 오래되었는지 어떻게 알 수 있나요?

alpine:latest와 같은 이미지 태그를 사용하는 경우, 이미지가 시간이 지남에 따라 변경됩니다.

변경될 때마다 매니페스트는 요청할 블롭에 대한 다른 정보를 포함합니다. Dependency Proxy는 매니페스트가 변경될 때마다 새로운 이미지를 가져오지 않습니다; 매니페스트가 오래된 경우에만 확인합니다.

Docker는 이미지 매니페스트에 대한 HEAD 요청을 속도 제한에 포함하지 않습니다.

alpine:latest에 대해 HEAD 요청을 하고, 헤더에서 반환된 다이제스트(체크섬) 값을 보고 매니페스트가 변경되었는지 확인할 수 있습니다.

Dependency Proxy는 모든 요청을 HEAD 요청으로 시작합니다.

매니페스트가 오래된 경우에만 새로운 이미지를 끌어옵니다.

예를 들어, 파이프라인이 5분마다 node:latest를 가져오는 경우, Dependency Proxy는 전체 이미지를 캐시하고 node:latest가 변경될 경우에만 업데이트합니다.

따라서 6시간에 대한 이미지의 360개 요청(이는 Docker Hub 속도 제한을 초과함) 대신, 매니페스트가 그 시간 동안 변경되지 않는다면 단 하나의 풀 요청만 발생합니다.

Docker Hub 속도 제한 확인

Docker Hub에 대해 얼마나 많은 요청을 했고 얼마나 남았는지 궁금하다면, 다음 명령어를 런너에서 실행하거나 CI/CD 스크립트에서 사용할 수 있습니다:

# 이 명령을 실행하려면 jq가 설치되어 있어야 합니다.
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 작업에서 속도 제한 확인하기

이 예시는 jqcurl이 설치된 이미지를 사용하는 GitLab CI/CD 작업을 보여줍니다:

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

문제 해결

인증 오류: “HTTP Basic: Access Denied”

Dependency Proxy에 인증할 때 HTTP Basic: Access denied 오류가 발생하면 이중 인증 문제 해결 가이드를 참조하세요.

Dependency Proxy 연결 실패

서비스 별칭이 설정되지 않은 경우 docker:20.10.16 이미지가 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는 Dependency Proxy에 자동으로 인증합니다. 그러나 기본 Docker 엔진은 여전히 인증 해제 절차의 적용을 받습니다.

인증 메커니즘의 잘못된 설정은 HTTP Basic: Access denied403: 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 오류

이러한 오류는 작업을 실행하는 사용자가 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)
    

Access denied와 유사한 경우의 오류 메시지를 개선하기 위한 작업에 대한 자세한 정보는 문제 354826를 참조하세요.

exec format error 를 의존성 프록시에서 이미지를 실행할 때

참고:
이 문제는 해결되었습니다 GitLab 16.3에서.
셀프 관리 인스턴스가 16.2 이하인 경우 인스턴스를 16.3으로 업데이트하거나 아래에 문서화된 해결 방법을 사용할 수 있습니다.

이 오류는 GitLab 16.2 이하에서 ARM 기반 Docker 설치에서 의존성 프록시를 사용하려고 하면 발생합니다.
의존성 프록시는 특정 태그가 있는 이미지를_pull할 때_x86_64 아키텍처만 지원합니다.

해결 방법으로 이미지를 강제로 다른 아키텍처로 가져오려면 SHA256을 지정할 수 있습니다:

docker pull ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/library/docker:20.10.3@sha256:bc9dcf5c8e5908845acc6d34ab8824bca496d6d47d1b08af3baf4b3adb1bd8fe

이 예에서 bc9dcf5c8e5908845acc6d34ab8824bca496d6d47d1b08af3baf4b3adb1bd8fe는 ARM 기반 이미지의 SHA256입니다.

MissingFile 복원 후 오류

MissingFile 또는 Cannot read file 오류가 발생하면
백업 아카이브
gitlab-rails/shared/dependency_proxy/의 내용이 포함되어 있지 않기 때문일 수 있습니다.

알려진 문제를 해결하려면 rsync, scp 또는 유사한 도구를 사용하여 백업의 원본이었던 GitLab 인스턴스에서 영향을 받는 파일이나 전체 gitlab-rails/shared/dependency_proxy/ 폴더 구조를 복사할 수 있습니다.

데이터가 필요하지 않은 경우 다음을 사용하여 데이터베이스 항목을 삭제할 수 있습니다:

gitlab-psql -c "DELETE FROM dependency_proxy_blobs; DELETE FROM dependency_proxy_blob_states; DELETE FROM dependency_proxy_manifest_states; DELETE FROM dependency_proxy_manifests;"