컨테이너 이미지를 위한 Dependency Proxy
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
요약
GitLab의 컨테이너 이미지용 Dependency Proxy는 자주 사용하는 업스트림 이미지에 활용할 수 있는 로컬 프록시입니다. CI/CD에서는 Dependency Proxy가 요청을 받아 레지스트리의 업스트림 이미지를 반환하며, 풀 스루 캐시 역할을 합니다.
GitLab의 컨테이너 이미지용 Dependency Proxy는 자주 사용하는 업스트림 이미지에 활용할 수 있는 로컬 프록시입니다.
CI/CD에서는 Dependency Proxy가 요청을 받아 레지스트리의 업스트림 이미지를 반환하며, 풀 스루 캐시 역할을 합니다.
사전 요구 사항#
컨테이너 이미지용 Dependency Proxy를 사용하려면 GitLab 인스턴스에서 이 기능이 활성화되어 있어야 합니다. 기본적으로 활성화되어 있지만, 관리자가 이를 끌 수 있습니다.
GitLab Self-Managed에서는 관리자가 인증된 Dependency Proxy 요청에 대한 전용 속도 제한을 구성할 수도 있습니다. 자세한 내용은 사용자 및 IP 속도 제한을 참고합니다.
지원되는 이미지 및 패키지#
다음 이미지와 패키지를 지원합니다.
| 이미지/패키지 | GitLab 버전 |
|---|---|
| Docker | 14.0+ |
추가 예정 목록은 방향성 페이지를 참고합니다.
그룹의 Dependency Proxy 활성화 또는 비활성화#
히스토리
- GitLab 17.0에서 필요한 권한이 Maintainer에서 Owner로 변경되었습니다.
그룹의 Dependency Proxy를 활성화하거나 비활성화하려면:
- 상단 바에서 Search or go to를 선택하고 그룹을 찾습니다.
- 왼쪽 사이드바에서 Settings > Packages and registries를 선택합니다.
- Dependency Proxy 섹션을 확장합니다.
- 프록시를 활성화하려면 Enable Proxy를 켭니다. 비활성화하려면 토글을 끕니다.
이 설정은 그룹의 Dependency Proxy에만 영향을 미칩니다. 전체 GitLab 인스턴스에 대해 Dependency Proxy를 켜거나 끄는 작업은 관리자만 할 수 있습니다.
컨테이너 이미지용 Dependency Proxy 보기#
컨테이너 이미지용 Dependency Proxy를 보려면:
- 상단 바에서 Search or go to를 선택하고 그룹을 찾습니다.
- 왼쪽 사이드바에서 Operate > Dependency Proxy를 선택합니다.
Dependency Proxy는 프로젝트에서는 사용할 수 없습니다.
Docker 이미지에 Dependency Proxy 사용#
GitLab을 Docker 이미지의 소스로 사용할 수 있습니다.
사전 요구 사항:
- 이미지가 Docker Hub에 저장되어 있어야 합니다.
컨테이너 이미지용 Dependency Proxy 인증#
히스토리
컨테이너 이미지용 Dependency Proxy는 그룹과 연결된 공간에 Docker 이미지를 저장하므로, Dependency Proxy에 인증해야 합니다.
프라이빗 레지스트리의 이미지 사용 안내를 따르되,
registry.example.com:5000 대신 포트가 없는 GitLab 도메인 gitlab.example.com을 사용합니다.
Admin Mode는 컨테이너 이미지용 Dependency Proxy 인증 과정에는 적용되지 않습니다. Admin Mode를 활성화한 관리자가 admin_mode 스코프 없이 개인 액세스 토큰을 만들면, Admin Mode가 활성화되어 있어도 해당 토큰이 동작합니다.
예를 들어 수동으로 로그인하려면 다음과 같이 실행합니다:
echo "$CONTAINER_REGISTRY_PASSWORD" | docker login gitlab.example.com --username my_username --password-stdin
다음을 사용해 인증할 수 있습니다:
- GitLab 사용자 이름과 비밀번호.
- GitLab CLI.
- 개인 액세스 토큰.
- 그룹 배포 토큰.
- 그룹의 그룹 액세스 토큰.
토큰 스코프는 다음 중 하나로 설정해야 합니다:
api: 전체 API 액세스를 부여합니다.read_registry: 컨테이너 레지스트리에 대한 읽기 전용 액세스를 부여합니다.write_registry: 컨테이너 레지스트리에 대한 읽기 및 쓰기 액세스를 부여합니다.read_virtual_registry: 그룹 수준 Dependency Proxy를 통한 컨테이너 이미지 읽기 전용(풀) 액세스를 부여합니다. Dependency Proxy가 활성화된 경우에만 사용할 수 있습니다.write_virtual_registry: 캐시된 이미지 채우기와 정리를 포함해 그룹 수준 Dependency Proxy 캐시에 대한 쓰기 액세스를 부여합니다. 해당 캐시를 통한 풀 액세스도 부여합니다. 프로젝트 컨테이너 레지스트리에 대한 푸시 또는 삭제 액세스는 부여하지 않습니다. Dependency Proxy가 켜져 있을 때만 사용할 수 있습니다.
컨테이너 이미지용 Dependency Proxy로 인증할 때 토큰에는 다음 스코프 조합 중 하나가 포함되어야 합니다:
- 컨테이너 레지스트리 스코프:
read_registry및write_registry. - Dependency Proxy 스코프:
read_virtual_registry및write_virtual_registry. Dependency Proxy를 통해 이미지를 풀하면 GitLab은 그룹 수준 Dependency Proxy 캐시에 데이터를 씁니다.
개인 액세스 토큰 또는 사용자 이름과 비밀번호로 컨테이너 이미지용 Dependency Proxy에 접근하는 사용자는 이미지를 가져오는 그룹에서 Guest, Planner, Reporter, Developer, Maintainer 또는 Owner 권한이 있어야 합니다.
컨테이너 이미지용 Dependency Proxy는 Docker v2 토큰 인증 흐름을 따르며, 풀에 사용할 JWT를 클라이언트에 발행합니다. 인증 결과로 발행된 JWT는 일정 시간이 지나면 만료됩니다. 토큰이 만료되면 대부분의 Docker 클라이언트가 자격 증명을 저장해 두고 추가 작업 없이 새 토큰을 자동으로 요청합니다.
토큰 만료 시간은 구성할 수 있는 설정입니다. GitLab.com에서는 만료 시간이 15분입니다.
SAML SSO#
SSO 강제 적용이 활성화된 경우, 사용자는 컨테이너 이미지용 Dependency Proxy를 통해 이미지를 풀하기 전에 SSO로 로그인해야 합니다.
SSO 강제 적용은 자동 머지에도 영향을 미칩니다. 자동 머지가 트리거되기 전에 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-cli
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 변수를 사용해 개인 액세스 토큰이나 배포 토큰을 저장하고 참조할 수도 있습니다.
Docker Hub로 인증#
기본적으로 Dependency Proxy는 Docker Hub에서 이미지를 풀할 때 자격 증명을 사용하지 않습니다. Docker Hub 자격 증명이나 토큰으로 Docker Hub 인증을 구성할 수 있습니다.
Docker Hub 인증에는 다음을 사용할 수 있습니다:
- Docker Hub 사용자 이름과 비밀번호.
- 이 방법은 Single Sign-On(SSO)을 강제하는 Docker Hub 조직에서는 사용할 수 없습니다.
- Docker Hub Personal Access Token.
- Docker Hub Organization Access Token.
자격 증명 구성#
그룹의 Dependency Proxy에 Docker Hub 자격 증명을 설정하려면:
-
상단 바에서 Search or go to를 선택하고 그룹을 찾습니다.
-
왼쪽 사이드바에서 Settings > Packages and registries를 선택합니다.
-
Dependency Proxy 섹션을 확장합니다.
-
Enable Proxy를 켭니다.
-
Docker Hub authentication에서 자격 증명을 입력합니다:
- Identity는 사용자 이름(비밀번호 또는 Personal Access Token 사용 시) 또는 조직 이름(Organization Access Token 사용 시)입니다.
- Secret은 비밀번호, Personal Access Token 또는 Organization Access Token입니다.
두 필드를 모두 입력하거나 모두 비워 두어야 합니다. 두 필드를 모두 비워 두면 Docker Hub 요청은 인증 없이 전송됩니다.
GraphQL API를 사용한 자격 증명 구성#
GraphQL API로 Dependency Proxy 설정에 Docker Hub 자격 증명을 설정하려면:
-
GraphiQL로 이동합니다:
- GitLab.com에서는 https://gitlab.com/-/graphql-explorer를 사용합니다.
- GitLab Self-Managed에서는
https://gitlab.example.com/-/graphql-explorer를 사용합니다.
-
GraphiQL에서 다음 뮤테이션을 입력합니다:
mutation { updateDependencyProxySettings(input: { enabled: true, identity: "<identity>", secret: "<secret>", groupPath: "<group path>" }) { dependencyProxySetting { enabled identity } errors } }각 항목의 의미는 다음과 같습니다:
<identity>는 사용자 이름(비밀번호 또는 Personal Access Token 사용 시) 또는 조직 이름(Organization Access Token 사용 시)입니다.<secret>은 비밀번호, Personal Access Token 또는 Organization Access Token입니다.<group path>는 Dependency Proxy가 있는 그룹의 경로입니다.
-
Play를 선택합니다.
-
결과 창에 오류가 있는지 확인합니다.
자격 증명 확인#
Dependency Proxy 인증을 마친 뒤, Docker 이미지를 풀해 Docker Hub 자격 증명을 확인합니다:
docker pull gitlab.example.com/groupname/dependency_proxy/containers/alpine:latest
인증이 성공하면 Docker Hub Usage 대시보드에 활동이 표시됩니다.
Dependency Proxy 캐시에 Docker 이미지 저장#
Dependency Proxy 스토리지에 Docker 이미지를 저장하려면:
-
상단 바에서 Search or go to를 선택하고 그룹을 찾습니다.
-
왼쪽 사이드바에서 Operate > Dependency Proxy를 선택합니다.
-
Dependency Proxy image prefix를 복사합니다.
-
다음 명령 중 하나를 사용합니다. 아래 예시에서 이미지는
alpine:latest입니다. -
다이제스트로 이미지를 풀해 가져올 이미지 버전을 정확히 지정할 수도 있습니다.
-
.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 이미지를 풀하고 blob을 GitLab 서버에 캐시합니다. 다음에 같은 이미지를 풀하면 GitLab은 Docker Hub에서 이미지에 대한 최신 정보를 가져오되, 기존 blob은 GitLab 서버에서 제공합니다.
스토리지 사용량 줄이기#
컨테이너 이미지용 Dependency Proxy의 스토리지 사용량을 줄이는 방법은 Dependency Proxy 스토리지 사용량 줄이기를 참고합니다.
Docker Hub 속도 제한 및 Dependency Proxy#
Dependency Proxy로 Docker Hub 속도 제한을 피하는 방법 영상을 참고합니다.
Docker Hub는 풀에 대한 속도 제한을 적용합니다. GitLab CI/CD 구성이 Docker Hub의 이미지를 사용하면, job이 실행될 때마다 풀 1회로 집계될 수 있습니다. 이 제한을 피하려면 Dependency Proxy 캐시에서 이미지를 풀할 수 있습니다.
docker pull 같은 명령이나 .gitlab-ci.yml 파일의 image: foo:latest로 이미지를
풀하면, Docker 클라이언트는 다음과 같은 요청을 연달아 보냅니다:
- 이미지 매니페스트를 요청합니다. 매니페스트에는 이미지를 빌드하는 방법에 대한 정보가 담겨 있습니다.
- Docker 클라이언트는 매니페스트를 사용해 blob이라고도 하는 레이어를 한 번에 하나씩 요청합니다.
Docker Hub 속도 제한은 매니페스트에 대한 GET 요청 수를 기준으로 합니다. Dependency Proxy는 해당 이미지의 매니페스트와 blob을 모두 캐시하므로, 같은 이미지를 다시 요청할 때는 Docker Hub에 접속하지 않아도 됩니다.
캐시된 태그 이미지의 만료 확인 방식#
alpine:latest 같은 이미지 태그를 사용하면 이미지는 시간이 지나면서
변경됩니다. 변경될 때마다 매니페스트에는 요청할 blob에 대한 정보가 다르게
담깁니다. Dependency Proxy는 매니페스트가 바뀔 때마다 새 이미지를 풀하지 않고,
매니페스트가 만료된 경우에만 확인합니다.
Docker는 이미지 매니페스트에 대한 HEAD 요청은 속도 제한에 집계하지 않습니다.
alpine:latest에 HEAD 요청을 보내고 헤더로 반환된 다이제스트(체크섬)
값을 확인해 매니페스트가 변경되었는지 판단할 수 있습니다.
Dependency Proxy는 모든 요청을 HEAD 요청으로 시작합니다. 매니페스트가 만료된 경우에만 새 이미지를 풀합니다.
예를 들어 파이프라인이 5분마다 node:latest를 풀한다면,
Dependency Proxy는 이미지 전체를 캐시하고 node:latest가 변경될 때만
갱신합니다. 따라서 6시간 동안 이미지 요청이 360회(Docker Hub 속도 제한을 초과하는
횟수) 발생하는 대신, 그 사이에 매니페스트가 변경되지 않는 한
풀은 1회만 발생합니다.
Docker Hub 속도 제한 확인#
Docker Hub에 보낸 요청 수와 남은 요청 수를 확인하려면, 러너에서 또는 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 job에서 속도 제한 확인#
다음 예시는 jq와 curl이 설치된 이미지를 사용하는 GitLab CI/CD job입니다:
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 오류가 발생하면 2단계 인증 문제 해결 가이드를 참고합니다.
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 job에서 Dependency Proxy 인증 문제#
GitLab Runner는 Dependency Proxy에 자동으로 인증합니다. 그러나 기반 Docker 엔진은 여전히 자체 인가 확인 절차를 따릅니다.
인증 메커니즘 구성이 잘못되면 HTTP Basic: Access denied 및 403: Access forbidden 오류가 발생할 수 있습니다.
job 로그에서 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 오류#
다음과 같은 오류는 job을 실행하는 사용자가 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을 참고합니다.
백업 복원 후 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;"