컨테이너 레지스트리 트러블슈팅
특정 문제를 조사하기 전에 다음 트러블슈팅 단계를 시도해 보세요: Docker 클라이언트와 GitLab 서버의 시스템 시계가 동기화되어 있는지 확인합니다(예: NTP를 통해). S3 기반 레지스트리의 경우 IAM 권한과 S3 자격 증명(지역 포함)이 올바른지 확인합니다.
특정 문제를 조사하기 전에 다음 트러블슈팅 단계를 시도해 보세요:
-
Docker 클라이언트와 GitLab 서버의 시스템 시계가 동기화되어 있는지 확인합니다(예: NTP를 통해).
-
S3 기반 레지스트리의 경우 IAM 권한과 S3 자격 증명(지역 포함)이 올바른지 확인합니다. 자세한 내용은 샘플 IAM 정책을 참조하세요.
-
레지스트리 로그(예:
/var/log/gitlab/registry/current)와 GitLab 프로덕션 로그(예:/var/log/gitlab/gitlab-rails/production.log)에서 오류를 확인합니다. -
컨테이너 레지스트리의 NGINX 구성 파일(예:
/var/opt/gitlab/nginx/conf/gitlab-registry.conf)을 검토하여 어떤 포트가 요청을 수신하는지 확인합니다. -
요청이 컨테이너 레지스트리로 올바르게 전달되는지 확인합니다:
curl --verbose --noproxy "*" https://<hostname>:<port>/v2/_catalog응답에는
service="container_registry"를 포함하는Www-Authenticate: Bearer줄이 있어야 합니다. 예를 들어:< HTTP/1.1 401 Unauthorized < Server: nginx < Date: Fri, 07 Mar 2025 08:24:43 GMT < Content-Type: application/json < Content-Length: 162 < Connection: keep-alive < Docker-Distribution-Api-Version: registry/2.0 < Www-Authenticate: Bearer realm="https://<hostname>/jwt/auth",service="container_registry",scope="registry:catalog:*" < X-Content-Type-Options: nosniff < {"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail": [{"Type":"registry","Class":"","Name":"catalog","ProjectPath":"","Action":"*"}]}]} * Connection #0 to host <hostname> left intact
오류: ... x509: certificate signed by unknown authority#
컨테이너 레지스트리에 자체 서명 인증서를 사용할 때 CI/CD 파이프라인 작업에서 다음과 유사한 오류가 발생할 수 있습니다:
Error response from daemon: Get registry.example.com/v1/users/: x509: certificate signed by unknown authority
이 오류는 명령을 실행하는 Docker 데몬이 자체 서명 인증서가 아닌 인증된 인증 기관(CA)이 서명한 인증서를 기대하기 때문에 발생합니다.
이 오류를 해결하려면 자체 서명 인증서를 신뢰하도록 Docker를 구성하세요. Docker 구성에 대한 도움말은 자체 서명 인증서 구성을 참조하세요.
추가 정보는 이슈 18239를 참조하세요.
Docker 로그인 시도 실패: 'token signed by untrusted key'#
레지스트리는 GitLab에 자격 증명 유효성 검사를 의존합니다. 레지스트리가 유효한 로그인 시도를 인증하지 못하면 다음 오류 메시지가 표시됩니다:
# docker login gitlab.company.com:4567
Username: user
Password:
Error response from daemon: login attempt to https://gitlab.company.com:4567/v2/ failed with status: 401 Unauthorized
더 구체적으로, 이것은 /var/log/gitlab/registry/current 로그 파일에 나타납니다:
level=info
msg="token signed by untrusted key with ID: "TOKE:NL6Q:7PW6:EXAM:PLET:OKEN:BG27:RCIB:D2S3:EXAM:PLET:OKEN""
level=warning msg="error authorizing context: invalid token" go.version=go1.12.7 http.request.host="gitlab.company.com:4567"
http.request.id=74613829-2655-4f96-8991-1c9fe33869b8 http.request.method=GET http.request.remoteaddr=10.72.11.20
http.request.uri="/v2/" http.request.useragent="docker/19.03.2 go/go1.12.8 git-commit/6a30dfc
kernel/3.10.0-693.2.2.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.2 \(linux\))"
(가독성을 위해 줄 바꿈이 추가되었습니다.)
GitLab은 인증서 키 쌍의 두 면의 내용을 사용하여 레지스트리에 대한 인증 토큰을 암호화합니다. 이 메시지는 해당 내용이 일치하지 않음을 의미합니다.
사용 중인 파일을 확인합니다:
-
grep -A6 'auth:' /var/opt/gitlab/registry/config.yml## Container registry certificate auth: token: realm: https://gitlab.my.net/jwt/auth service: container_registry issuer: omnibus-gitlab-issuer --> rootcertbundle: /var/opt/gitlab/registry/gitlab-registry.crt autoredirect: false -
grep -A9 'Container Registry' /var/opt/gitlab/gitlab-rails/etc/gitlab.yml## Container registry key registry: enabled: true host: gitlab.company.com port: 4567 api_url: http://127.0.0.1:5000 # internal address to the registry, is used by GitLab to directly communicate with API path: /var/opt/gitlab/gitlab-rails/shared/registry --> key: /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key issuer: omnibus-gitlab-issuer notification_secret:
이 openssl 명령의 출력이 일치해야 하며, 이는 인증서-키 쌍이 일치한다는 것을 증명합니다:
/opt/gitlab/embedded/bin/openssl x509 -noout -modulus -in /var/opt/gitlab/registry/gitlab-registry.crt | /opt/gitlab/embedded/bin/openssl sha256
/opt/gitlab/embedded/bin/openssl rsa -noout -modulus -in /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key | /opt/gitlab/embedded/bin/openssl sha256
인증서의 두 부분이 일치하지 않는 경우, 파일을 제거하고 gitlab-ctl reconfigure를 실행하여 쌍을 재생성하세요. /etc/gitlab/gitlab-secrets.json에 기존 값이 있으면 이를 사용하여 쌍이 재생성됩니다. 새 쌍을 생성하려면 gitlab-ctl reconfigure를 실행하기 전에 /etc/gitlab/gitlab-secrets.json의 registry 섹션을 삭제하세요.
자동 생성된 자체 서명 쌍을 자체 인증서로 재정의하고 내용이 일치하는지 확인했다면 /etc/gitlab/gitlab-secrets.json의 registry 섹션을 삭제하고 gitlab-ctl reconfigure를 실행할 수 있습니다.
GitLab 레지스트리로 대용량 이미지를 푸시할 때 AWS S3 오류#
AWS S3와 GitLab 레지스트리를 사용할 때 대용량 이미지를 푸시할 때 오류가 발생할 수 있습니다. 레지스트리 로그에서 다음 오류를 확인하세요:
level=error msg="response completed with error" err.code=unknown err.detail="unexpected EOF" err.message="unknown error"
이 오류를 해결하려면 레지스트리 구성에 chunksize 값을 지정하세요. 25000000(25 MB)에서 50000000(50 MB) 사이의 값으로 시작하세요.
-
/etc/gitlab/gitlab.rb를 편집합니다:registry['storage'] = { 's3' => { 'accesskey' => 'AKIAKIAKI', 'secretkey' => 'secret123', 'bucket' => 'gitlab-registry-bucket-AKIAKIAKI', 'chunksize' => 25000000 } } -
파일을 저장하고 변경 사항을 적용하려면 GitLab을 재구성합니다.
-
config/gitlab.yml을 편집합니다:storage: s3: accesskey: 'AKIAKIAKI' secretkey: 'secret123' bucket: 'gitlab-registry-bucket-AKIAKIAKI' chunksize: 25000000 -
파일을 저장하고 변경 사항을 적용하려면 GitLab을 재시작합니다.
이전 Docker 클라이언트 지원#
GitLab과 함께 제공되는 Docker 컨테이너 레지스트리는 기본적으로 schema1 매니페스트를 비활성화합니다. 이전 Docker 클라이언트(1.9 이하)를 아직 사용 중인 경우 이미지 푸시 시 오류가 발생할 수 있습니다. 자세한 내용은 이슈 4145를 참조하세요.
이전 버전과의 호환성을 위한 구성 옵션을 추가할 수 있습니다.
-
/etc/gitlab/gitlab.rb를 편집합니다:registry['compatibility_schema1_enabled'] = true -
파일을 저장하고 변경 사항을 적용하려면 GitLab을 재구성합니다.
-
레지스트리를 배포할 때 만든 YAML 구성 파일을 편집합니다. 다음 스니펫을 추가합니다:
compatibility: schema1: enabled: true -
변경 사항을 적용하려면 레지스트리를 재시작합니다.
Docker 연결 오류#
그룹, 프로젝트 또는 브랜치 이름에 특수 문자가 있는 경우 Docker 연결 오류가 발생할 수 있습니다. 특수 문자에는 다음이 포함될 수 있습니다:
- 앞에 오는 밑줄
- 뒤에 오는 하이픈/대시
- 이중 하이픈/대시
이를 해결하기 위해 그룹 경로를 변경하거나, 프로젝트 경로를 변경하거나, 브랜치 이름을 변경할 수 있습니다. 또한 전체 인스턴스에 대해 이 오류를 방지하기 위해 푸시 규칙을 만드는 옵션도 있습니다.
이미지 푸시 오류#
docker login이 성공해도 Docker 이미지를 푸시할 때 재시도 루프에서 멈출 수 있습니다.
이 문제는 NGINX가 레지스트리로 헤더를 제대로 전달하지 않을 때 발생하는데, 일반적으로 SSL이 타사 역방향 프록시로 오프로드되는 사용자 정의 설정에서 발생합니다.
자세한 내용은 NGINX 프록시를 통한 Docker 푸시 실패 - 32B 레이어 전송 시도 #970을 참조하세요.
이 문제를 해결하려면 레지스트리에서 상대 URL을 활성화하도록 NGINX 구성을 업데이트합니다:
-
/etc/gitlab/gitlab.rb를 편집합니다:registry['env'] = { "REGISTRY_HTTP_RELATIVEURLS" => true } -
파일을 저장하고 변경 사항을 적용하려면 GitLab을 재구성합니다.
-
레지스트리를 배포할 때 만든 YAML 구성 파일을 편집합니다. 다음 스니펫을 추가합니다:
http: relativeurls: true -
파일을 저장하고 변경 사항을 적용하려면 GitLab을 재시작합니다.
-
docker-compose.yaml파일을 편집합니다:GITLAB_OMNIBUS_CONFIG: | registry['env'] = { "REGISTRY_HTTP_RELATIVEURLS" => true } -
문제가 지속되면 두 URL이 모두 HTTPS를 사용하는지 확인합니다:
GITLAB_OMNIBUS_CONFIG: | external_url 'https://git.example.com' registry_external_url 'https://git.example.com:5050' -
파일을 저장하고 컨테이너를 재시작합니다:
sudo docker restart gitlab
레지스트리 디버그 서버 활성화#
컨테이너 레지스트리 디버그 서버를 사용하여 문제를 진단할 수 있습니다. 디버그 엔드포인트는 메트릭과 상태를 모니터링하고 프로파일링도 수행할 수 있습니다.
디버그 엔드포인트에서 민감한 정보가 제공될 수 있습니다. 프로덕션 환경에서는 디버그 엔드포인트에 대한 액세스를 잠금 설정해야 합니다.
옵션인 디버그 서버는 gitlab.rb 구성에서 레지스트리 디버그 주소를 설정하여 활성화할 수 있습니다.
registry['debug_addr'] = "localhost:5001"
설정을 추가한 후 변경 사항을 적용하려면 GitLab을 재구성합니다.
디버그 서버에서 디버그 출력을 요청하려면 curl을 사용합니다:
curl "localhost:5001/debug/health"
curl "localhost:5001/debug/vars"
Prometheus 메트릭#
Prometheus는 컨테이너 레지스트리의 성능 문제를 모니터링하고 트러블슈팅하는 데 사용할 수 있는 메트릭을 제공합니다.
다음 섹션에서:
- Prometheus 메트릭을 활성화하는 방법을 보여줍니다
- 컨테이너 레지스트리에서 내보낸 모든 Prometheus 메트릭을 구성 요소별로 정리하여 나열합니다
Prometheus 메트릭 활성화#
사전 조건:
- 레지스트리 디버그 서버를 활성화해야 합니다.
Prometheus 메트릭을 활성화하려면 gitlab.rb에 다음 구성을 추가합니다:
# Enable Prometheus metrics
registry['debug'] = {
'prometheus' => {
'enabled' => true,
'path' => '/metrics'
}
}
변경 사항을 적용하려면 GitLab을 재구성합니다.
디버그 서버에서 메트릭을 요청하려면 curl을 사용합니다:
curl "localhost:5001/metrics"
알림 메트릭#
카운터#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_notifications_events_total |
총 이벤트 수. | type, action, artifact, endpoint |
type: Successes, Failures, Events, Dropped |
registry_notifications_status_total |
알림 엔드포인트에서 수신한 HTTP 상태 코드별 응답 수. | code, endpoint |
code: HTTP 상태 코드(예: 200 OK 또는 404 Not Found) |
registry_notifications_errors_total |
전송 중 오류가 발생한 이벤트 수. 전송 요청이 재시도될 수 있습니다. | endpoint |
string: '...' |
registry_notifications_delivery_total |
전달되었거나 손실된 이벤트 수. 재시도 횟수가 소진되면 이벤트가 손실됩니다. | endpoint, delivery_type |
delivery_type: delivered, lost |
게이지#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_notifications_pending |
큐 길이로 표시되는 큐의 보류 중인 이벤트 게이지. | endpoint |
string: '...' |
히스토그램#
| 메트릭 이름 | 설명 | 레이블 | 버킷 |
|---|---|---|---|
registry_notifications_retries_count |
누적 전달 재시도 횟수 히스토그램. | endpoint |
[0, 1, 2, 3, 5, 10, 15, 20, 30, 50] |
registry_notifications_http_latency_seconds |
HTTP 전달 지연 시간 히스토그램. | endpoint |
[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 25, 50, 100] (초) |
registry_notifications_total_latency_seconds |
총 전달 지연 시간 히스토그램. | endpoint |
[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 25, 50, 100] (초) |
일괄 백그라운드 마이그레이션(BBM) 메트릭#
카운터#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_bbm_runs_total |
일괄 마이그레이션 워커 실행 카운터. | 없음 | 없음 |
registry_bbm_migrated_tuples_total |
마이그레이션된 총 일괄 마이그레이션 레코드 카운터. | migration_name, migration_id |
string: '...' |
게이지#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_bbm_job_batch_size |
일괄 마이그레이션 작업의 배치 크기 게이지. | migration_name, migration_id |
string: '...' |
registry_database_bbm_progress_percent |
백그라운드 마이그레이션 진행 비율(0-100). | migration_id, migration_name, status |
string: '...' |
히스토그램#
| 메트릭 이름 | 설명 | 레이블 | 버킷 |
|---|---|---|---|
registry_bbm_run_duration_seconds |
일괄 마이그레이션 워커 실행 지연 시간 히스토그램. | 없음 | [0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600] (0.5초~1시간) |
registry_bbm_job_duration_seconds |
일괄 마이그레이션 작업 지연 시간 히스토그램. | migration_name, migration_id |
[0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600] (0.5초~1시간) |
registry_bbm_query_duration_seconds |
일괄 마이그레이션 데이터베이스 쿼리 지연 시간 히스토그램. | migration_name, migration_id |
[0.5, 1, 2, 5, 10, 15, 30, 60, 120, 300, 600, 900, 1800, 3600] (0.5초~1시간) |
registry_bbm_sleep_duration_seconds |
BBM 워커 실행 사이 슬립 시간 히스토그램. | worker |
[0.5, 1, 5, 15, 30, 60, 300, 600, 900, 1800, 3600, 7200, 10800, 21600, 43200, 86400] (500ms~24시간) |
데이터베이스 메트릭#
카운터#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_database_queries_total |
데이터베이스 쿼리 카운터. | name |
string: '...' |
registry_database_lb_lsn_cache_hits_total |
데이터베이스 로드 밸런싱 LSN 캐시 적중 및 미스 카운터. | result |
result: hit, miss |
registry_database_lb_pool_events_total |
데이터베이스 로드 밸런서 풀에서 추가되거나 제거된 복제본 카운터. | event, reason |
event: replica_added, replica_removed, replica_quarantined, replica_reintegratedreason: replication_lag, connectivity, removed_from_dns, discovered |
registry_database_lb_targets_total |
데이터베이스 로드 밸런싱 중 기본 및 복제본 대상 선정 카운터. | target_type, fallback, reason |
target_type: primary, replicafallback: true, falsereason: selected, no_cache, no_replica, error, not_up_to_date, all_quarantined |
게이지#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_database_lb_pool_size |
로드 밸런서 풀의 현재 복제본 수 게이지. | 없음 | 없음 |
registry_database_lb_pool_status |
로드 밸런서 풀에 있는 각 복제본의 현재 상태 게이지. | replica, status |
status: online, quarantined |
registry_database_lb_lag_bytes |
각 복제본의 복제 지연 바이트 게이지. | replica |
string: '...' |
registry_database_migrations_total |
총 데이터베이스 마이그레이션 수(적용됨 + 보류 중) 게이지. | migration_type |
migration_type: pre_deployment, post_deployment |
registry_database_rows |
query_name 레이블로 정의된 데이터베이스 테이블의 행 수 게이지. |
query_name |
query_name: gc_blob_review_queue, gc_manifest_review_queue, gc_blob_review_queue_overdue, gc_manifest_review_queue_overdue, applied_pre_migrations, applied_post_migrations |
히스토그램#
| 메트릭 이름 | 설명 | 레이블 | 버킷 |
|---|---|---|---|
registry_database_query_duration_seconds |
데이터베이스 쿼리 지연 시간 히스토그램. | name |
Prometheus 기본 버킷. 1 |
registry_database_lb_lsn_cache_operation_duration_seconds |
데이터베이스 로드 밸런싱 LSN 캐시 작업 지연 시간 히스토그램. | operation, error |
operation: set, geterror: true, falsePrometheus 기본 버킷. 1 |
registry_database_lb_lookup_seconds |
데이터베이스 로드 밸런싱 DNS 조회 지연 시간 히스토그램. | lookup_type, error |
lookup_type: srv, hosterror: true, falsePrometheus 기본 버킷. 1 |
registry_database_lb_lag_seconds |
각 복제본의 초 단위 복제 지연 히스토그램. | replica |
[0.001, 0.01, 0.1, 0.5, 1, 5, 10, 20, 30, 60] (1ms~60초) |
registry_database_row_count_collection_duration_seconds |
단일 실행에서 모든 데이터베이스 행 수 쿼리를 수집하는 총 시간 히스토그램. | 없음 | [0.1, 0.5, 1, 2, 5, 10, 30, 60] (100ms~60초) |
각주:
- Prometheus 기본 버킷 값:
[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10](초)
가비지 수집(GC) 메트릭#
카운터#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_gc_runs_total |
온라인 GC 워커 실행 카운터. | worker, noop, error, dangling, event |
noop: true, falseerror: true, falsedangling: true, false |
registry_gc_deletes_total |
온라인 GC 중 삭제된 아티팩트 카운터. | backend, artifact |
backend: storage, databaseartifact: blob, manifest |
registry_gc_storage_deleted_bytes_total |
온라인 GC 중 스토리지에서 삭제된 바이트 카운터. | media_type |
string: '...' |
registry_gc_postpones_total |
온라인 GC 검토 연기 카운터. | worker |
string: '...' |
히스토그램#
| 메트릭 이름 | 설명 | 레이블 | 버킷 |
|---|---|---|---|
registry_gc_run_duration_seconds |
온라인 GC 워커 실행 지연 시간 히스토그램. | worker, noop, error, dangling, event |
noop: true, falseerror: true, falsedangling: true, falsePrometheus 기본 버킷. 1 |
registry_gc_delete_duration_seconds |
온라인 GC 중 아티팩트 삭제 지연 시간 히스토그램. | backend, artifact, error |
backend: storage, databaseartifact: blob, manifesterror: true, falsePrometheus 기본 버킷. 1 |
registry_gc_sleep_duration_seconds |
온라인 GC 워커 실행 사이 슬립 시간 히스토그램. | worker |
[0.5, 1, 5, 15, 30, 60, 300, 600, 900, 1800, 3600, 7200, 10800, 21600, 43200, 86400] (500ms~24시간) |
각주:
- Prometheus 기본 버킷 값:
[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10](초)
스토리지 메트릭#
카운터#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_storage_cdn_redirects_total |
Blob 다운로드에 대한 CDN 리디렉션 카운터. | backend, bypass, bypass_reason |
bypass: true, false |
registry_storage_rate_limit_total |
속도 제한에 도달한 스토리지 드라이버 요청 카운터. | 없음 | 없음 |
registry_storage_storage_backend_retries_total |
스토리지 백엔드와 통신 중 재시도 카운터. | retry_type |
retry_type: native, custom |
registry_storage_urlcache_requests_total |
URL 캐시 미들웨어 요청 카운터. | result, reason |
result: hit, miss |
registry_storage_access_tracker_dropped_events |
시간 초과로 인해 액세스 추적기에서 삭제된 이벤트 카운터. | 없음 | 없음 |
게이지#
| 메트릭 이름 | 설명 | 레이블 | 레이블 값 |
|---|---|---|---|
registry_storage_object_accesses_topn |
가장 자주 액세스되는 상위 N개 객체에 대한 총 액세스 수. | top_n |
top_n: 1, 10, 100, 1000, 10000, all |
히스토그램#
| 메트릭 이름 | 설명 | 레이블 | 버킷 |
|---|---|---|---|
registry_storage_blob_download_bytes |
스토리지 백엔드의 Blob 다운로드 크기 히스토그램. | redirect |
redirect: true, false[524288, 1048576, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 3221225472, 4294967296, 5368709120, 6442450944, 7516192768, 8589934592, 9663676416, 10737418240, 21474836480, 32212254720, 42949672960, 53687091200] (512KiB~50GiB) |
registry_storage_blob_upload_bytes |
스토리지 백엔드의 새 Blob 업로드 바이트 히스토그램. | 없음 | [524288, 1048576, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 3221225472, 4294967296, 5368709120, 6442450944, 7516192768, 8589934592, 9663676416, 10737418240, 21474836480, 32212254720, 42949672960, 53687091200] (512KiB~50GiB) |
registry_storage_urlcache_object_size |
URL 캐시의 객체 크기 히스토그램. | 없음 | [100, 250, 500, 750, 1000, 1500, 2048, 3072, 5120, 10240] (100바이트~10KiB) |
registry_storage_object_accesses_distribution |
모든 객체의 액세스 수 분포. | 없음 | 지수 버킷: [10, 20, 40, 80, 160, 320, 640, 1280, 2560, 5120, 10240] |
레지스트리 디버그 로그 활성화#
컨테이너 레지스트리의 문제를 트러블슈팅하는 데 도움이 되는 디버그 로그를 활성화할 수 있습니다.
디버그 로그에는 인증 세부 정보, 토큰 또는 리포지터리 정보와 같은 민감한 정보가 포함될 수 있습니다. 필요한 경우에만 디버그 로그를 활성화하고 트러블슈팅이 완료되면 비활성화하세요.
-
/var/opt/gitlab/registry/config.yml을 편집합니다:level: debug -
파일을 저장하고 레지스트리를 재시작합니다:
sudo gitlab-ctl restart registry
이 구성은 임시적이며 gitlab-ctl reconfigure를 실행하면 삭제됩니다.
-
Helm 값을 내보냅니다:
helm get values gitlab > gitlab_values.yaml -
gitlab_values.yaml을 편집합니다:registry: log: level: debug -
파일을 저장하고 새 값을 적용합니다:
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab --namespace <namespace>
레지스트리 Prometheus 메트릭 활성화#
디버그 서버가 활성화된 경우 Prometheus 메트릭도 활성화할 수 있습니다. 이 엔드포인트는 거의 모든 레지스트리 작업과 관련된 매우 상세한 원격 측정 데이터를 노출합니다.
registry['debug'] = {
'prometheus' => {
'enabled' => true,
'path' => '/metrics'
}
}
Prometheus에서 디버그 출력을 요청하려면 curl을 사용합니다:
curl "localhost:5001/debug/metrics"
이름이 빈 태그#
AWS DataSync를 사용하여 레지스트리 데이터를 S3 버킷 간에 복사하면 대상 버킷에 있는 각 컨테이너 리포지터리의 루트 경로에 빈 메타데이터 객체가 생성됩니다. 이로 인해 레지스트리는 이러한 파일을 GitLab UI 및 API에서 이름 없이 표시되는 태그로 해석합니다. 자세한 내용은 이 이슈를 참조하세요.
이를 수정하려면 다음 두 가지 방법 중 하나를 사용할 수 있습니다:
-
AWS CLI
rm명령을 사용하여 영향 받은 각 리포지터리의 루트에서 빈 객체를 제거합니다. 끝에 오는/에 특별히 주의하고--recursive옵션을 사용하지 않도록 하세요:aws s3 rm s3://<bucket>/docker/registry/v2/repositories/<path to repository>/ -
AWS CLI
sync명령을 사용하여 레지스트리 데이터를 새 버킷으로 복사하고 이를 사용하도록 레지스트리를 구성합니다. 이렇게 하면 빈 객체가 남아 있습니다.
고급 트러블슈팅#
S3 설정과 관련된 문제를 진단하는 방법을 구체적인 예를 통해 설명합니다.
정리 정책 조사#
정리 정책이 태그를 삭제했거나 삭제하지 않은 이유가 확실하지 않은 경우, Rails 콘솔에서 아래 스크립트를 실행하여 정책을 한 줄씩 실행하세요. 이는 정책의 문제를 진단하는 데 도움이 될 수 있습니다.
repo = ContainerRepository.find(<repository_id>)
policy = repo.project.container_expiration_policy
tags = repo.tags
tags.map(&:name)
tags.reject!(&:latest?)
tags.map(&:name)
regex_delete = ::Gitlab::UntrustedRegexp.new("\\A#{policy.name_regex}\\z")
regex_retain = ::Gitlab::UntrustedRegexp.new("\\A#{policy.name_regex_keep}\\z")
tags.select! { |tag| regex_delete.match?(tag.name) && !regex_retain.match?(tag.name) }
tags.map(&:name)
now = DateTime.current
tags.sort_by! { |tag| tag.created_at || now }.reverse! # Lengthy operation
tags = tags.drop(policy.keep_n)
tags.map(&:name)
older_than_timestamp = ChronicDuration.parse(policy.older_than).seconds.ago
tags.select! { |tag| tag.created_at && tag.created_at < older_than_timestamp }
tags.map(&:name)
- 스크립트는 삭제할 태그 목록(
tags)을 빌드합니다. tags.map(&:name)은 제거할 태그 목록을 출력합니다. 이는 시간이 걸리는 작업일 수 있습니다.- 각 필터 후
tags목록을 확인하여 삭제하려는 태그가 포함되어 있는지 확인합니다.
푸시 중 예기치 않은 403 오류#
사용자가 S3 기반 레지스트리를 활성화하려고 했습니다. docker login 단계는 정상적으로 진행되었습니다. 그러나 이미지를 푸시할 때 출력이 다음과 같이 표시되었습니다:
The push refers to a repository [s3-testing.myregistry.com:5050/root/docker-test/docker-image]
dc5e59c14160: Pushing [==================================================>] 14.85 kB
03c20c1a019a: Pushing [==================================================>] 2.048 kB
a08f14ef632e: Pushing [==================================================>] 2.048 kB
228950524c88: Pushing 2.048 kB
6a8ecde4cc03: Pushing [==> ] 9.901 MB/205.7 MB
5f70bf18a086: Pushing 1.024 kB
737f40e80b7f: Waiting
82b57dbc5385: Waiting
19429b698a22: Waiting
9436069b92a3: Waiting
error parsing HTTP 403 response body: unexpected end of JSON input: ""
이 오류는 403이 GitLab Rails 애플리케이션, Docker 레지스트리 또는 다른 곳에서 오는 것인지 명확하지 않아 모호합니다. 이 경우 로그인이 성공했다는 것을 알고 있으므로 클라이언트와 레지스트리 간의 통신을 확인해야 합니다.
Docker 클라이언트와 레지스트리 간의 REST API는 Docker 설명서에 설명되어 있습니다. 일반적으로 Wireshark나 tcpdump를 사용하여 트래픽을 캡처하고 문제가 발생한 위치를 확인합니다. 그러나 Docker 클라이언트와 서버 간의 모든 통신은 HTTPS를 통해 이루어지므로 개인 키를 알더라도 트래픽을 신속하게 복호화하는 것이 약간 어렵습니다. 대신 어떻게 할 수 있을까요?
한 가지 방법은 비보안 레지스트리를 설정하여 HTTPS를 비활성화하는 것입니다. 이것은 보안 허점을 유발할 수 있으며 로컬 테스트에만 권장됩니다. 프로덕션 시스템을 가지고 있고 이 방법을 사용할 수 없거나 사용하고 싶지 않다면 다른 방법인 mitmproxy(중간자 프록시)를 사용할 수 있습니다.
mitmproxy#
mitmproxy를 사용하면 클라이언트와 서버 사이에 프록시를 배치하여 모든 트래픽을 검사할 수 있습니다. 한 가지 어려움은 시스템이 이것이 작동하려면 mitmproxy SSL 인증서를 신뢰해야 한다는 것입니다.
다음 설치 지침은 Ubuntu를 실행 중이라고 가정합니다:
-
mitmproxy --port 9000을 실행하여 인증서를 생성합니다. Control-C를 눌러 종료합니다. -
~/.mitmproxy의 인증서를 시스템에 설치합니다:sudo cp ~/.mitmproxy/mitmproxy-ca-cert.pem /usr/local/share/ca-certificates/mitmproxy-ca-cert.crt sudo update-ca-certificates
성공하면 출력에 인증서가 추가되었다고 표시되어야 합니다:
Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.
인증서가 제대로 설치되었는지 확인하려면 다음을 실행합니다:
mitmproxy --listen-port 9000
이 명령은 포트 9000에서 mitmproxy를 실행합니다. 다른 창에서 다음을 실행합니다:
curl --proxy "http://localhost:9000" "https://httpbin.org/status/200"
모든 것이 올바르게 설정되면 mitmproxy 창에 정보가 표시되고 curl 명령에서 오류가 생성되지 않습니다.
프록시를 통해 Docker 데몬 실행#
Docker가 프록시를 통해 연결하려면 적절한 환경 변수로 Docker 데몬을 시작해야 합니다. 가장 쉬운 방법은 Docker를 종료(예: sudo initctl stop docker)한 다음 직접 Docker를 실행하는 것입니다. 루트 권한으로 다음을 실행합니다:
export HTTP_PROXY="http://localhost:9000"
export HTTPS_PROXY="http://localhost:9000"
docker daemon --debug # or dockerd --debug
이 명령은 Docker 데몬을 시작하고 모든 연결을 mitmproxy를 통해 프록시합니다.
Docker 클라이언트 실행#
이제 mitmproxy와 Docker가 실행 중이므로 로그인을 시도하고 컨테이너 이미지를 푸시할 수 있습니다. 이 작업을 수행하려면 루트로 실행해야 할 수도 있습니다. 예를 들어:
docker login example.s3.amazonaws.com:5050
docker push example.s3.amazonaws.com:5050/root/docker-test/docker-image
이전 예시에서 mitmproxy 창에서 다음 추적을 볼 수 있습니다:
PUT https://example.s3.amazonaws.com:4567/v2/root/docker-test/blobs/uploads/(UUID)/(QUERYSTRING)
← 201 text/plain [no content] 661ms
HEAD https://example.s3.amazonaws.com:4567/v2/root/docker-test/blobs/sha256:(SHA)
← 307 application/octet-stream [no content] 93ms
HEAD https://example.s3.amazonaws.com:4567/v2/root/docker-test/blobs/sha256:(SHA)
← 307 application/octet-stream [no content] 101ms
HEAD https://example.s3.amazonaws.com:4567/v2/root/docker-test/blobs/sha256:(SHA)
← 307 application/octet-stream [no content] 87ms
HEAD https://amazonaws.example.com/docker/registry/vs/blobs/sha256/dd/(UUID)/data(QUERYSTRING)
← 403 application/xml [no content] 80ms
HEAD https://amazonaws.example.com/docker/registry/vs/blobs/sha256/dd/(UUID)/data(QUERYSTRING)
← 403 application/xml [no content] 62ms
이 출력은 다음을 보여줍니다:
- 초기 PUT 요청이
201상태 코드로 정상적으로 처리되었습니다. 201이 클라이언트를 Amazon S3 버킷으로 리디렉션했습니다.- AWS 버킷에 대한 HEAD 요청이
403 Unauthorized를 보고했습니다.
이것은 무엇을 의미할까요? 이것은 S3 사용자가 HEAD 요청을 수행할 적절한 권한이 없다는 것을 강력하게 시사합니다. 해결 방법: IAM 권한을 다시 확인하세요. 올바른 권한이 설정된 후 오류가 사라졌습니다.
gitlab-registry.key 누락으로 컨테이너 리포지터리 삭제 불가#
GitLab 인스턴스의 컨테이너 레지스트리를 비활성화하고 컨테이너 리포지터리가 있는 프로젝트를 제거하려고 하면 다음 오류가 발생합니다:
Errno::ENOENT: No such file or directory @ rb_sysopen - /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key
이 경우 다음 단계를 따르세요:
-
gitlab.rb에서 컨테이너 레지스트리의 인스턴스 전체 설정을 일시적으로 활성화합니다:gitlab_rails['registry_enabled'] = true -
파일을 저장하고 변경 사항을 적용하려면 GitLab을 재구성합니다.
-
제거를 다시 시도합니다.
일반적인 방법으로 리포지터리를 제거할 수 없는 경우 GitLab Rails 콘솔을 사용하여 강제로 프로젝트를 제거할 수 있습니다:
# Path to the project you'd like to remove
prj = Project.find_by_full_path(<project_path>)
# The following will delete the project's container registry, so be sure to double-check the path beforehand!
if prj.has_container_registry_tags?
prj.container_repositories.each { |p| p.destroy }
end
레지스트리 서비스가 IPv4 대신 IPv6 주소에서 수신#
GitLab 서버에서 localhost 호스트 이름이 IPv6 루프백 주소(::1)로 해석되고 GitLab이 레지스트리 서비스를 IPv4 루프백 주소(127.0.0.1)에서 사용 가능하다고 예상하는 경우 다음 오류가 표시될 수 있습니다:
request: "GET /v2/ HTTP/1.1", upstream: "http://[::1]:5000/v2/", host: "registry.example.com:5005"
[error] 1201#0: *13442797 connect() failed (111: Connection refused) while connecting to upstream, client: x.x.x.x, server: registry.example.com, request: "GET /v2/<path> HTTP/1.1", upstream: "http://[::1]:5000/v2/<path>", host: "registry.example.com:5005"
이 오류를 수정하려면 /etc/gitlab/gitlab.rb에서 registry['registry_http_addr']를 IPv4 주소로 변경하세요. 예를 들어:
registry['registry_http_addr'] = "127.0.0.1:5000"
자세한 내용은 이슈 5449를 참조하세요.
Google Cloud Storage(GCS)에서 푸시 실패 및 높은 CPU 사용량#
GCS를 백엔드로 사용하는 레지스트리에 컨테이너 이미지를 푸시할 때 502 Bad Gateway 오류가 발생할 수 있습니다. 대용량 이미지를 푸시할 때 레지스트리에서 CPU 사용량이 급증할 수도 있습니다.
이 문제는 레지스트리가 HTTP/2 프로토콜을 사용하여 GCS와 통신할 때 발생합니다.
해결 방법은 GODEBUG 환경 변수를 http2client=0으로 설정하여 레지스트리 배포에서 HTTP/2를 비활성화하는 것입니다.
자세한 내용은 이슈 1425를 참조하세요.
