컨테이너 레지스트리 스토리지 줄이기

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

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

  • 사용 가능한 태그나 이미지 목록을 검색하는 데 시간이 더 걸립니다.
  • 이것들은 서버에 많은 스토리지 공간을 차지합니다.

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

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

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

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

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

자체 관리 인스턴스의 컨테이너 레지스트리 사용량은 볼 수 없지만, 이는 epic 5521에서 제안되었습니다.

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

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

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

  • 동일한 리포지토리에서 동일한 이미지를 여러 번 태그하는 경우.
  • 동일한 루트 네임스페이스 아래의 서로 다른 리포지토리에서 동일한 이미지를 태그하는 경우.

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

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

태그가 지정된 이미지에서 참조되는 레이어만 계산됩니다. 태그가 없는 이미지와 오로지 그것들에 의해 참조되는 레이어는 온라인 가비지 수집의 대상이 됩니다.
태그가 없는 이미지 레이어는 해당 기간 동안 참조되지 않으면 24시간 후에 자동으로 삭제됩니다.

이미지 레이어는 원본(일반적으로 압축된) 형식으로 저장 백엔드에 저장됩니다. 이는 특정 이미지 레이어에 대한 측정된 크기가
해당하는 이미지 매니페스트에 표시되는 크기와 일치해야 함을 의미합니다.

네임스페이스 사용량은 태그가 네임스페이스의 어떤 컨테이너 리포지토리에서 푸시되거나 삭제된 후 몇 분 내에 새로 고쳐집니다.

지연된 새로 고침

매우 큰 네임스페이스(약 1%의 네임스페이스)에 대해서는 실시간으로 최대 정확도로 컨테이너 레지스트리 사용량을 계산할 수 없습니다.
이러한 네임스페이스의 유지 관리자가 자신의 사용량을 볼 수 있도록 하기 위해 지연된 폴백 메커니즘이 있습니다.
자세한 내용은 epic 9413를 참조하세요.

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

  • 자동 가비지 수집 프로세스가 실행되고 태그가 없는 이미지 레이어가 삭제됩니다.
    사용자가 태그를 삭제하면 가비지 수집 실행이 24시간 후에 시작되도록 예약됩니다.
    이 실행 동안 이전에 태그가 지정된 이미지가 분석되며 다른 태그가 있는 이미지에 의해 참조되지 않는 경우 레이어가 삭제됩니다.
    삭제된 레이어가 있는 경우 네임스페이스 사용량이 업데이트됩니다.
  • 네임스페이스의 레지스트리 사용량이 충분히 줄어들어 GitLab이 최대 정확도로 측정할 수 있게 됩니다.
    네임스페이스의 사용량이 줄어들면 측정이 자동으로 지연에서 정밀한 사용량 측정으로 전환됩니다.
    UI에서 어떤 측정 방법이 사용되는지 확인할 수 있는 곳은 없지만,
    issue 386468에서는 이를 개선할 것을 제안합니다.

정리 정책

  • 필요한 권한은 GitLab 15.0에서 개발자에서 유지 관리자로 변경되었습니다.

정리 정책은 컨테이너 레지스트리에서 태그를 제거하는 데 사용할 수 있는 예약 작업입니다. 정의된 프로젝트에 대해 정규 표현식 패턴과 일치하는 태그가 제거됩니다. 기본 레이어 및 이미지는 유지됩니다.

어떤 태그와도 관련이 없는 기본 레이어 및 이미지를 삭제하려면 관리자가 -m 스위치와 함께 가비지 수집을 사용할 수 있습니다.

정리 정책 활성화

경고:
성능 이유로, 컨테이너 이미지가 없는 GitLab.com의 프로젝트에 대해 활성화된 정리 정책은 자동으로 비활성화됩니다.

정리 정책 작동 방식

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

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

정리 정책:

  1. 주어진 리포지터리에 대한 모든 태그를 목록으로 수집합니다.

  2. latest라는 태그를 제외합니다.

  3. name_regex(만료할 태그)를 평가하여 일치하지 않는 이름을 제외합니다.

  4. name_regex_keep 값(보존할 태그)과 일치하는 태그를 제외합니다.

  5. 매니페스트가 없는 태그(사용자 인터페이스의 옵션에 포함되지 않음)를 제외합니다.

  6. 남은 태그를 created_date로 정렬합니다.

  7. keep_n 값(유지할 태그 수)을 기반으로 N 태그를 제외합니다.

  8. older_than 값(만료 간격)보다 최근의 태그를 제외합니다.

  9. 목록에서 컨테이너 레지스트리의 남은 태그를 삭제합니다.

경고:
GitLab.com에서 정리 정책의 실행 시간은 제한됩니다. 정책이 실행된 후 일부 태그가 컨테이너 레지스트리에 남을 수 있습니다. 정책이 다음에 실행될 때 남은 태그가 포함됩니다. 모든 태그를 삭제하려면 여러 번 실행해야 할 수 있습니다.

경고:
GitLab 자체 관리 설치는 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, v43v42입니다. 규칙은 다음과 같은 우선순위로 적용된다고 해석할 수 있습니다:

  1. 유지 규칙은 가장 높은 우선순위를 가집니다. 태그는 어느 규칙과 일치할 때 유지해야 합니다.
    • latest 태그는 항상 유지되어야 합니다.
    • production-v44, production-v43, 그리고 production-v42 태그는 일치하는 태그 유지 규칙과 일치하므로 유지되어야 합니다.
    • v44 태그는 가장 최근 것이므로 가장 최근 유지 규칙과 일치하므로 유지되어야 합니다.
  2. 삭제 규칙은 낮은 우선순위를 가지며, 태그는 모든 규칙이 일치할 때만 삭제됩니다.
    유지 규칙과 일치하지 않는 태그(dev-44, dev-v43, dev-v42, v43, 및 v42)의 경우:
    • dev-44dev-437일 이상 된 태그 삭제 규칙과 일치하지 않으므로 유지됩니다.
    • dev-v42, v43v427일 이상 된 태그 삭제일치하는 태그 삭제 규칙 모두와 일치하므로 이 세 태그는 삭제될 수 있습니다.

정리 정책 만들기

API 또는 UI에서 정리 정책을 만들 수 있습니다.

UI에서 정리 정책을 만들려면:

  1. 왼쪽 사이드바에서 검색 또는 이동을 선택하고 프로젝트를 찾습니다.

  2. 설정 > 패키지 및 레지스트리를 선택합니다.

  3. 정리 정책 섹션에서 정리 규칙 설정을 선택합니다.

  4. 필드를 완료합니다:

    필드 설명
    전환 정책을 켜거나 끕니다.
    정리 실행 정책이 얼마나 자주 실행되어야 하는지.
    최신 유지 각 이미지에 대해 항상 유지할 태그 수.
    일치하는 태그 유지 어떤 태그를 보존할지를 결정하는 정규 표현식 패턴. latest 태그는 항상 보존됩니다. 모든 태그에 대해 .*를 사용하세요. 다른 정규 표현식 패턴 예시를 참조하세요.
    X일보다 오래된 태그 제거 X일보다 오래된 태그만 제거합니다.
    일치하는 태그 제거 어떤 태그를 제거할지를 결정하는 정규 표현식 패턴. 이 값은 비어 있을 수 없습니다. 모든 태그에 대해 .*를 사용하세요. 다른 정규 표현식 패턴 예시를 참조하세요.

    주의: 유지 및 제거 정규 표현식 패턴은 자동으로 \A\Z 앵커로 둘러싸여 있으므로 포함할 필요가 없습니다. 그러나 정규 표현식 패턴을 선택하고 테스트할 때 이를 고려해야 합니다.

  5. 저장을 선택합니다.

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

주요: 정책을 편집하고 저장을 다시 선택하면 간격이 초기화됩니다.

정규 표현식 패턴 예시

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

GitLab은 정리 정책의 정규 표현식에 RE2 구문을 사용합니다.

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

  • 모든 태그 일치:

    .*
    

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

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

    v.+
    
  • 이름이 main인 태그만 일치:

    main
    
  • 이름이 release인 태그 또는 시작하는 태그 일치:

    release.*
    
  • v로 시작하거나 main이라는 태그 또는 release로 시작하는 태그 일치:

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

리소스 절약을 위한 정리 한도 설정

  • 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에 저장됩니다. 기본적으로 활성화되어 있습니다.

자체 관리 인스턴스의 경우 이러한 설정은 Rails 콘솔에서 업데이트할 수 있습니다:

ApplicationSetting.last.update(container_registry_expiration_policies_worker_capacity: 3)

또한 관리자 영역에서 사용할 수 있습니다:

  1. 왼쪽 사이드바에서 맨 아래, 관리자를 선택합니다.

  2. 설정 > CI/CD를 선택합니다.

  3. 컨테이너 레지스트리를 확장합니다.

정리 정책 API 사용

GitLab API를 사용하여 정리 정책을 설정, 업데이트 및 비활성화할 수 있습니다.

예시:

  • 모든 태그를 선택하고, 이미지당 최소 1개의 태그를 유지하며, 14일 이상된 태그를 정리하고, 매달 한 번 실행하며, 이름이 main인 이미지는 보존하고, 정책이 활성화된 경우:

    curl --fail-with-body --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 백그라운드 작업이 정체되거나 완전히 실패할 수 있습니다.

컨테이너 레지스트리 저장소 축소 옵션 더보기

프로젝트에서 사용하는 컨테이너 레지스트리 저장소를 줄이기 위해 사용할 수 있는 다른 옵션은 다음과 같습니다:

정리 정책 문제 해결

정리 정책 업데이트 중 문제가 발생했습니다.

이 오류 메시지가 표시되면 정규 표현식 패턴이 유효한지 확인하세요.

[Golang] 구문을 사용하여 regex101 regex tester로 테스트할 수 있습니다.

일반적인 정규 표현식 패턴 예시를 확인하세요.

정리 정책이 태그를 삭제하지 않음

여러 가지 이유가 있을 수 있습니다:

  • GitLab 자체 관리 인스턴스에서 1000개 이상의 태그가 컨테이너 레지스트리에 있는 경우, 컨테이너 레지스트리 토큰 만료 문제에 직면할 수 있으며, 로그에서 error authorizing context: invalid token 메시지가 나타날 수 있습니다.

    이를 해결하기 위한 두 가지 해결 방법은 다음과 같습니다:

    • 정리 정책에 대한 제한 설정을 통해 정리 실행을 제한하고 만료된 토큰 오류를 피할 수 있습니다.

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

대안으로, 삭제할 태그 목록을 생성하고 해당 목록을 사용하여 태그를 삭제할 수 있습니다. 목록을 생성하고 태그를 삭제하려면:

  1. 다음 셸 스크립트를 실행합니다. for 루프 바로 앞의 명령은 루프를 시작할 때 list_o_tags.out을 항상 재초기화합니다. 이 명령을 실행한 후 모든 태그의 이름이 list_o_tags.out 파일에 작성됩니다:

    # 특정 컨테이너 저장소의 모든 태그 목록을 가져오고 [페이징](../../../api/rest/index.md#pagination)을 고려합니다.
    echo -n "" > list_o_tags.out; for i in {1..N}; do curl --fail-with-body --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
    

    이 명령 세트는 created_at 날짜가 한 달 이상 지난 모든 태그를 나열하는 /tmp/list_o_tags.out 파일을 생성합니다.

  2. list_o_tags.out 파일에서 유지할 태그를 제거합니다. 예를 들어, sed를 사용하여 파일을 구문 분석하고 태그를 제거할 수 있습니다.

    # 파일에서 `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
    
  3. list_o_tags.out 파일이 삭제할 태그만 포함하고 있는지 다시 확인합니다.

  4. list_o_tags.out 파일에 있는 태그를 삭제하기 위해 이 셸 스크립트를 실행합니다:

    # list_o_tags.out를 반복하여 한 번에 하나의 태그를 삭제
    while read -r LINE || [[ -n $LINE ]]; do echo ${LINE}; curl --fail-with-body --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