컨테이너 레지스트리 리포지터리 축소

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

컨테이너 레지스트리는 레지스트리 사용량을 관리하지 않으면 시간이 지남에 따라 크기가 커질 수 있습니다. 예를 들어,
대량의 이미지나 태그를 추가하는 경우:

  • 사용 가능한 태그나 이미지 디렉터리을 검색하는 데 시간이 더 오래 걸립니다.
  • 서버의 저장 공간을 많이 차지합니다.

불필요한 이미지 및 태그를 삭제하고 컨테이너 레지스트리 사용량을 자동으로 관리하도록 정리 정책을 설정해야 합니다.

컨테이너 레지스트리 사용량 보기

Tier: Free, Premium, Ultimate Offering: GitLab.com

컨테이너 레지스트리의 리포지터리 사용량을 보려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.
  2. 설정 > 사용량 할당을 선택합니다.

Self-managed 인스턴스의 경우 컨테이너 레지스트리 사용량을 볼 수 없지만, 이는 에픽 5521에서 제안되고 있습니다.

컨테이너 레지스트리 사용량 계산 방법

컨테이너 레지스트리에 저장된 이미지 레이어는 루트 네임스페이스 수준에서 중복 제거됩니다.

이미지는 다음과 같은 경우에만 한 번만 계산됩니다:

  • 동일한 이미지를 동일한 리포지터리에서 여러 번 태깅하는 경우.
  • 동일한 이미지를 동일한 루트 네임스페이스 내에서 다른 리포지터리에 태깅하는 경우.

이미지 레이어는 다음과 같은 경우에만 한 번만 계산됩니다:

  • 동일한 이미지 레이어를 동일한 컨테이너 리포지터리, 프로젝트 또는 그룹에서 여러 이미지에 공유하는 경우.
  • 동일한 이미지 레이어를 다른 리포지터리에서 공유하는 경우.

태그가 지정된 이미지에만 참조된 레이어만 고려됩니다. 태그가 없는 이미지와 해당 레이어는 온라인 가비지 수집의 대상입니다. 태그가 없는 이미지 레이어는 해당 기간 동안 참조되지 않은 경우 24시간 후 자동으로 삭제됩니다.

이미지 레이어는 원래(일반적으로 압축된) 형식으로 저장 공간 백엔드에 저장됩니다. 따라서 특정 이미지 레이어의 메트릭된 크기는 해당 이미지 매니페스트에 표시된 크기와 일치해야 합니다.

태그가 푸시되거나 삭제된 후 몇 분 후에 네임스페이스 사용량이 갱신됩니다.

지연된 갱신

실시간으로 매우 큰 네임스페이스 (전체 네임스페이스의 약 1%)의 컨테이너 레지스트리 사용량을 최대 정확도로 계산하는 것은 불가능합니다. 이러한 네임스페이스의 유지 관리자가 사용량을 볼 수 있도록 하기 위해 지연된 대안 메커니즘이 있습니다. 자세한 내용은 에픽 9413을 참조하십시오.

네임스페이스의 사용량이 최대 정확도로 계산될 수 없는 경우, GitLab은 지연된 방법으로 전환됩니다. 지연된 방법에서 표시된 사용량 크기는 해당 네임스페이스 내의 모든 고유 이미지 레이어의 합계입니다. 태그가 지정되지 않은 이미지 레이어는 무시되지 않습니다. 그 결과로 표시된 사용량 크기는 태그를 삭제한 후에는 크게 변하지 않을 수 있습니다. 대신 사용량 값은 다음 시점에서만 변경됩니다:

  • 자동 가비지 수집 프로세스가 실행되어 태그를 삭제합니다. 사용자가 태그를 삭제한 후 24시간 후에 가비지 수집 실행이 예약됩니다. 실행 중에 이전에 태그를 지정한 이미지가 분석되고 다른 태그가 참조하지 않으면 해당 레이어가 삭제됩니다. 레이어가 삭제되면 네임스페이스 사용량이 갱신됩니다.
  • 네임스페이스의 레지스트리 사용량이 제한 미만으로 축소되어 사용량 메트릭이 자동으로 지연에서 정확한 사용량 메트릭으로 전환됩니다. 사용량이 제한을 벗어나면 메트릭 방법이 자동으로 지연에서 정확한 메트릭으로 변경됩니다. UI에 어떤 메트릭 방법이 사용되는지 확인할 수 있는 곳은 없지만, 이슈 386468에서 개선이 제안되고 있습니다.

정리 정책

  • GitLab 13.2에서 “만료 정책”에서 “정리 정책”으로 이름이 변경되었습니다.
  • GitLab 15.0에서 필요한 권한이 개발자에서 유지자로 변경되었습니다.

정리 정책은 컨테이너 레지스트리에서 태그를 제거하는 예약 작업입니다. 정책이 정의된 프로젝트의 경우 정규식 패턴과 일치하는 태그가 제거됩니다. 그러나 기본 레이어와 이미지는 유지됩니다.

태그가 지정되지 않은 레이어 및 이미지를 삭제하려면 관리자는 가비지 수집-m 옵션과 함께 사용할 수 있습니다.

정리 정책 활성화

이러한 예외 사항에 대해 모든 프로젝트에 대해 정리 정책을 실행할 수 있습니다:

  • Self-managed GitLab 인스턴스의 경우 프로젝트는 GitLab 12.8 이후에 생성되어야 합니다. 그러나 관리자는 GitLab 애플리케이션 설정에서 container_expiration_policies_enable_historic_entries를 true로 설정함으로써 모든 프로젝트 (GitLab 12.8 이전에 생성된 프로젝트도 포함)에 대해 정리 정책을 활성화할 수 있습니다. 또한 Rails 콘솔에서 다음 명령을 실행할 수 있습니다:

    ApplicationSetting.last.update(container_expiration_policies_enable_historic_entries: true)
    

    모든 프로젝트에서 정리 정책을 활성화하면 성능에 영향을 줄 수 있으며, 특히 외부 레지스트리를 사용하는 경우에 해당합니다.

caution
성능 문제로 인해 GitLab.com의 프로젝트에서는 컨테이너 이미지가 없는 경우 활성화된 정리 정책이 자동으로 비활성화됩니다.

정리 정책 작동 방식

정리 정책은 컨테이너 레지스트리의 모든 태그를 수집하고 삭제할 태그만 남을 때까지 태그를 제외합니다.

정리 정책은 태그 이름을 기반으로 이미지를 검색합니다. 전체 경로 일치 지원은 이슈 281071에서 추적됩니다.

정리 정책:

  1. 특정 리포지터리의 모든 태그를 디렉터리으로 수집합니다.
  2. latest라는 이름의 태그를 제외합니다.
  3. name_regex (만료될 태그)를 평가하여 일치하지 않는 이름을 제외합니다.
  4. name_regex_keep 값 (보존할 태그)과 일치하는 태그를 제외합니다.
  5. 매니페스트가 없는 태그는 제외합니다 (UI의 옵션에 포함되지 않음).
  6. created_date에 따라 남은 태그를 정렬합니다.
  7. keep_n 값 (유지할 태그 수)을 기준으로 최신 태그를 제외합니다.
  8. older_than 값 (만료 간격)보다 최신인 태그를 제외합니다.
  9. 디렉터리에서 남은 태그를 컨테이너 레지스트리에서 삭제합니다.
caution
GitLab.com에서 정리 정책의 실행 시간은 제한됩니다. 정책이 실행된 후에도 일부 태그가 컨테이너 레지스트리에 남을 수 있습니다. 다음으로 정책이 실행되면 남은 태그가 포함됩니다. 모든 태그를 삭제하려면 여러 실행이 필요할 수 있습니다.
caution
GitLab Self-managed 설치는 Docker Registry HTTP API V2 사양을 준수하는 타사 컨테이너 레지스트리를 지원합니다. 그러나 이 사양에는 태그 삭제 작업이 포함되어 있지 않습니다. 따라서 GitLab은 타사 컨테이너 레지스트리와 상호 작용할 때 태그 삭제를 위해 우회 방법을 사용합니다. 자세한 내용은 이슈 15737을 참조하십시오. 가능한 구현 변형으로 인해 이러한 우회 방법이 모든 타사 레지스트리에서 예측 가능한 방식으로 작동한다는 보장은 없습니다. GitLab 컨테이너 레지스트리를 사용하는 경우에는 특별한 태그 삭제 작업을 구현했으므로 정리 정책을 일관되고 예측 가능하게 사용할 수 있습니다.

예제 정리 정책 워크플로우

정리 정책의 유지 및 제거 규칙 간 상호작용은 복잡할 수 있습니다. 예를 들어, 다음과 같은 정리 정책 구성을 가진 프로젝트가 있는 경우:

  • 가장 최근 것 유지: 이미지 이름 당 1개의 태그.
  • 일치하는 태그 유지: production-.*
  • 이전보다 오래된 태그 제거: 7일.
  • 일치하는 태그 제거: .*.

그리고 다음과 같은 태그를 포함하는 컨테이너 리포지터리가 있는 경우:

  • latest, 2시간 전 발행.
  • production-v44, 3일 전 발행.
  • production-v43, 6일 전 발행.
  • production-v42, 11일 전 발행.
  • dev-v44, 2일 전 발행.
  • dev-v43, 5일 전 발행.
  • dev-v42, 10일 전 발행.
  • v44, 어제 발행.
  • v43, 12일 전 발행.
  • v42, 20일 전 발행.

이 예제에서 다음 정리 실행에서 삭제 될 태그는 dev-v42, v43, 및 v42입니다. 규칙의 해석 방법은 다음과 같은 우선순위로 적용됩니다:

  1. 유지 규칙이 가장 높은 우선순위를 갖습니다. 태그는 어떤 규칙에 일치하는 경우 보존되어야 합니다.
    • latest 태그는 항상 보존되므로 유지되어야 합니다.
    • production-v44, production-v43, 그리고 production-v42 태그는 일치하는 태그 유지 규칙과 일치하기 때문에 보존되어야 합니다.
    • v44 태그는 가장 최근이므로 가장 최근 것 유지 규칙과 일치하여 보존되어야 합니다.
  2. 제거 규칙은 낮은 우선순위를 갖고, 태그는 모든 규칙이 일치하는 경우에만 삭제됩니다. 유지 규칙과 일치하지 않는 경우의 태그 (dev-44, dev-v43, dev-v42, v43, 그리고 v42)에 대해:
    • dev-44dev-43이전보다 오래된 태그 제거와 일치하지 않으므로 유지됩니다.
    • dev-v42, v43, 와 v42이전보다 오래된 태그 제거일치하는 태그 제거 규칙 둘 다 일치하므로 이 세 개의 태그는 삭제할 수 있습니다.

정리 정책 생성

UI에서 정리 정책을 생성할 수 있습니다:

  1. 프로젝트에 대해 설정 > 패키지 및 레지스트리로 이동합니다.
  2. 정리 정책 섹션에서 정리 규칙 설정을 선택합니다.
  3. 다음 필드를 완성합니다:

    필드 설명
    토글 정책을 켜거나 끕니다.
    정리 실행 정책을 실행해야 하는 빈도
    가장 최근 것 유지 각 이미지에 대해 항상 유지해야 할 태그 수
    일치하는 태그 유지 보존해야 할 태그를 결정하는 정규식 패턴. latest 태그는 항상 보존됩니다. 모든 태그에 대해 .*을 사용합니다. 다른 정규식 패턴 예시를 참조하세요.
    이전보다 오래된 태그 제거 X일 전보다 오래된 태그만 제거
    일치하는 태그 제거 제거해야 할 태그를 결정하는 정규식 패턴. 이 값은 빈 값이 될 수 없습니다. 모든 태그에 대해 .*을 사용합니다. 다른 정규식 패턴 예시를 참조하세요.
  4. 저장을 선택합니다.

정책은 선택한 예약된 간격에 따라 실행됩니다.

note
정책을 편집하고 다시 저장을 선택하면 간격이 재설정됩니다.

정규식 패턴 예시

UI와 API에서 정리 정책은 어떤 태그를 보존하거나 제거할지를 결정하기 위해 정규식 패턴을 사용합니다.

정규식 패턴은 자동으로 \A\Z 앵커로 둘러싸입니다. 따라서 정규식 패턴에는 어떤 \A, \Z, ^ 또는 $ 토큰도 포함할 필요가 없습니다.

다음은 사용할 수 있는 정규식 패턴의 몇 가지 예시입니다:

  • 모든 태그와 일치:

    .*
    

    이 패턴은 만료 정규식의 기본값입니다.

  • v로 시작하는 태그와 일치:

    v.+
    
  • main이라는 태그와 일치:

    main
    
  • release로 시작하거나 release로 시작하는 태그와 일치:

    release.*
    
  • v로 시작하거나 main으로 지정하거나 release로 시작하는 태그와 일치:

    (?:v.+|main|release.*)
    

리소스 보존을 위한 정리 제한 설정

  • GitLab 13.9에 도입되었습니다. container_registry_expiration_policies_throttling이라는 플래그로.
  • GitLab 14.9에서 기본 활성화됩니다.
  • GitLab 15.0에서는 피처 플래그 container_registry_expiration_policies_throttling제거되었습니다.

정리 정책은 백그라운드 프로세스로 실행됩니다. 이 프로세스는 복잡하며 삭제할 태그의 수에 따라 완료하는 데 시간이 걸릴 수 있습니다.

서버 리소스 고갈을 방지하기 위해 다음 응용 프로그램 설정을 사용할 수 있습니다:

  • container_registry_expiration_policies_worker_capacity: 동시에 실행되는 최대 정리 작업자 수입니다. 이 값은 0보다 크거나 같아야 합니다. 백그라운드 작업자가 사용하는 리소스를 모니터링한 후에 이 값을 낮게 설정하고 증가시킬 수 있습니다. 모든 작업자를 제거하고 정리 정책을 실행하지 않으려면 이 값을 0으로 설정하면 됩니다. 기본값은 4입니다.
  • container_registry_delete_tags_service_timeout: 정리 프로세스가 태그 배치를 삭제하는 데 걸리는 최대 시간(초)입니다. 기본값은 250입니다.
  • container_registry_cleanup_tags_service_max_list_size: 단일 실행에서 삭제할 수 있는 최대 태그 수입니다. 추가 태그는 다른 실행에서 삭제해야 합니다. 해당 컨테이너 이미지가 올바르게 삭제되었는지 확인한 후에 이 값을 낮게 설정하고 증가시킬 수 있습니다. 기본값은 200입니다.
  • container_registry_expiration_policies_caching: 정책 실행 중에 태그 생성 타임스탬프 캐싱 기능을 활성화 또는 비활성화합니다. 캐시된 타임스탬프는 Redis에 저장됩니다. 기본적으로 활성화됩니다.

Self-managed 인스턴스의 경우 Rails 콘솔에서 이러한 설정을 업데이트할 수 있습니다:

ApplicationSetting.last.update(container_registry_expiration_policies_worker_capacity: 3)

이 설정은 관리 영역에서도 사용할 수 있습니다:

  1. 왼쪽 사이드바에서 가장 아래에 있는 관리 영역을 선택합니다.
  2. 설정 > CI/CD를 선택합니다.
  3. 컨테이너 레지스트리를 확장합니다.

cleanup policy API 사용

GitLab API를 사용하여 정책 설정, 업데이트, 해제를 할 수 있습니다.

예시:

  • 모든 태그를 선택하고 각 이미지당 적어도 1개의 태그를 유지하고, 14일 이전의 태그를 정리하고, 한 달에 한 번 실행하며, main이라는 이름을 가진 이미지는 보존하고 정책을 활성화합니다.

    curl --request PUT --header 'Content-Type: application/json;charset=UTF-8' --header "PRIVATE-TOKEN: <your_access_token>" \
         --data-binary '{"container_expiration_policy_attributes":{"cadence":"1month","enabled":true,"keep_n":1,"older_than":"14d","name_regex":".*","name_regex_keep":".*-main"}}' \
         "https://gitlab.example.com/api/v4/projects/2"
    

API를 사용할 때 cadence의 유효한 값은 다음과 같습니다:

  • 1d (매일)
  • 7d (매주)
  • 14d (2주마다)
  • 1month (매월)
  • 3month (분기마다)

API를 사용할 때 keep_n (이미지 이름당 유지되는 태그 수)의 유효한 값은 다음과 같습니다:

  • 1
  • 5
  • 10
  • 25
  • 50
  • 100

API를 사용할 때 older_than (자동으로 제거되는 태그까지의 일수)의 유효한 값은 다음과 같습니다:

  • 7d
  • 14d
  • 30d
  • 90d

자세한 내용은 API 문서를 참조하세요: 프로젝트 API 편집.

외부 컨테이너 레지스트리 사용

외부 컨테이너 레지스트리를 사용할 때 프로젝트에 정책을 실행하면 성능 리스크가 있을 수 있습니다. 프로젝트에서 수천 개의 태그를 제거하는 정책을 실행하면 GitLab 백그라운드 작업이 지연되거나 완전히 실패할 수 있습니다. GitLab 12.8 이전에 생성된 프로젝트의 경우, 태그 정리 정책은 삭제되는 태그의 수가 적을 때에만 활성화해야 합니다.

추가 컨테이너 레지스트리 리포지터리 축소 옵션

프로젝트에서 사용하는 컨테이너 레지스트리 리포지터리를 줄이기 위해 사용할 수 있는 몇 가지 옵션이 있습니다:

정책 문제 해결

정책을 업데이트하는 중에 문제가 발생했습니다.

이 오류 메시지를 보게 되면 유효한지 확인하기 위해 정규식 패턴을 확인하세요.

GitLab은 정책 정리를 위해 정규식으로 RE2 구문을 사용합니다. Golang 플레이버를 사용하여 regex101 정규식 테스터로 테스트할 수 있습니다. #regex-pattern-examples에서 일반적인 정규식 패턴 예제를 확인할 수 있습니다.

정책이 어떤 태그도 삭제하지 않음

이에는 다양한 이유가 있을 수 있습니다:

  • GitLab 13.6 이하에서 정책을 실행했을 때 예상했던대로 태그를 삭제하지 않습니다. 이는 정책이 일치하는 태그 제거 필드를 편집하지 않고 저장된 경우에 발생합니다. 이 필드는 플레이스홀더로써 회색으로 표시된 .* 값을 갖고 있습니다. 필드에 명시적으로 .* (또는 다른 정규식 패턴)을 입력하지 않으면 nil 값이 제출됩니다. 이 값은 저장된 정책이 어떤 태그와 일치하지 않도록 하기 때문에 발생합니다. 해결책으로 정책을 편집하세요. 일치하는 태그 제거 필드에 .*를 입력하고 저장하세요. 이 값은 모든 태그가 제거되어야 함을 나타냅니다.

  • GitLab Self-managed 인스턴스를 사용 중이고 컨테이너 리포지터리에 1000개 이상의 태그가 있는 경우, 로그에 error authorizing context: invalid token과 같은 컨테이너 레지스트리 토큰 만료 오류가 발생할 수 있습니다.

    이를 해결하기 위해 두 가지 해결책이 있습니다:

    • GitLab 13.9 이상 버전을 사용 중이라면, 정책을 위한 제한을 설정할 수 있습니다. 이는 정책 실행 시간을 제한하고 만료된 토큰 오류를 피할 수 있습니다.

    • 컨테이너 레지스트리 인증 토큰의 만료 지연을 연장할 수 있습니다. 이 값은 기본적으로 5분입니다. ApplicationSetting.last.update(container_registry_token_expire_delay: <integer>) 명령을 사용하여 원하는 분 수의 사용자 정의 값을 설정할 수 있습니다. 참고로, GitLab.com에서는 이 값을 15분으로 설정했습니다. 이 값을 높이면 권한 취소에 필요한 시간도 늘어납니다.

또 다른 방법으로 삭제할 태그의 디렉터리을 생성하고 그 디렉터리을 사용하여 태그를 삭제할 수 있습니다. 디렉터리을 생성하고 태그를 삭제하려면 다음을 수행하세요:

  1. 다음 쉘 스크립트를 실행합니다. for 루프를 시작할 때 명령은 항상 list_o_tags.out이 항상 다시 초기화됨을 보장합니다. 이 명령을 실행하면 모든 태그의 이름이 list_o_tags.out 파일에 작성됩니다:

    # [페이지네이션 고려](../../../api/rest/index.md#페이지네이션)하면서 특정 컨테이너 리포지터리의 모든 태그 디렉터리을 가져옵니다
    echo -n "" > list_o_tags.out; for i in {1..N}; do curl --header 'PRIVATE-TOKEN: <PAT>' "https://gitlab.example.com/api/v4/projects/<Project_id>/registry/repositories/<container_repo_id>/tags?per_page=100&page=${i}" | jq '.[].name' | sed 's:^.\(.*\).$:\1:' >> list_o_tags.out; done
    

    Rails 콘솔에 액세스할 수 있는 경우, 다음 명령을 입력하여 날짜로 제한된 태그 디렉터리을 검색할 수 있습니다:

    output = File.open( "/tmp/list_o_tags.out","w" )
    Project.find(<Project_id>).container_repositories.find(<container_repo_id>).tags.each do |tag|
      output << tag.name + "\n" if tag.created_at < 1.month.ago
    end;nil
    output.close
    

    이 명령 세트는 1개월 전에 만들어진 created_at 날짜가 있는 모든 태그를 나열하는 /tmp/list_o_tags.out 파일을 만듭니다.

  2. list_o_tags.out 파일에서 유지하려는 태그를 제거합니다. 예를 들어, 파일을 파싱하고 태그를 제거할 수 있습니다.

    Linux
    # 파일에서 `latest` 태그 제거
    sed -i '/latest/d' list_o_tags.out
       
    # 파일에서 처음 N개의 태그 제거
    sed -i '1,Nd' list_o_tags.out
       
    # 파일에서 `Av`로 시작하는 태그 제거
    sed -i '/^Av/d' list_o_tags.out
       
    # 파일에서 `_v3`로 끝나는 태그 제거
    sed -i '/_v3$/d' list_o_tags.out
    
    macOS
    # 파일에서 `latest` 태그 제거
    sed -i .bak '/latest/d' list_o_tags.out
       
    # 파일에서 처음 N개의 태그 제거
    sed -i .bak '1,Nd' list_o_tags.out
       
    # 파일에서 `Av`로 시작하는 태그 제거
    sed -i .bak '/^Av/d' list_o_tags.out
       
    # 파일에서 `_v3`로 끝나는 태그 제거
    sed -i .bak '/_v3$/d' list_o_tags.out
    
  3. list_o_tags.out 파일에 원하는 태그만 포함되었는지 확인하세요.

  4. 다음 쉘 스크립트를 실행하여 list_o_tags.out 파일의 태그를 삭제합니다:

    # list_o_tags.out을 반복하면서 한 번에 하나의 태그를 삭제합니다
    while read -r LINE || [[ -n $LINE ]]; do echo ${LINE}; curl --request DELETE --header 'PRIVATE-TOKEN: <PAT>' "https://gitlab.example.com/api/v4/projects/<Project_id>/registry/repositories/<container_repo_id>/tags/${LINE}"; sleep 0.1; echo; done < list_o_tags.out > delete.logs