저장소 크기
GitLab v19.5Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated
요약
Git 리포지터리의 크기는 성능과 스토리지 비용에 큰 영향을 줍니다. 리포지터리 크기는 리포지터리에 있는 모든 파일 크기의 합계입니다. 리포지터리 크기는 프로젝트 크기의 일부입니다. 리포지터리 크기를 확인하려면 다음과 같이 합니다:
Git 리포지터리의 크기는 성능과 스토리지 비용에 큰 영향을 줍니다. 압축, 하우스키핑을 비롯한 여러 요인 때문에 인스턴스마다 크기가 조금씩 다를 수 있습니다.
크기 계산#
리포지터리 크기는 리포지터리에 있는 모든 파일 크기의 합계입니다.
이 계산은 리포지터리의 해시 스토리지 경로에서
du --summarize --bytes를 실행하는 것과 비슷합니다.
크기는 리포지터리가 변경될 때 다시 계산되며, 15분에 한 번을 넘지 않습니다.
리포지터리 크기는 프로젝트 크기의 일부입니다. 프로젝트 개요 페이지의 Project information 아래에 표시되는 프로젝트 크기에는 리포지터리와 함께 LFS 객체, job 아티팩트, 패키지, 위키가 포함됩니다.
리포지터리 크기 확인#
사전 요구 사항:
- 프로젝트에 대한 Maintainer 또는 Owner 권한, 또는 네임스페이스에 대한 Owner 권한이 필요합니다.
리포지터리 크기를 확인하려면 다음과 같이 합니다:
- 상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
- 왼쪽 사이드바에서 Settings > Usage quotas를 선택합니다.
- Storage 탭을 선택합니다.
- 사용량 내역에서 Repository 행의 값을 확인합니다.
프로젝트가 사용하는 스토리지에 대한 자세한 내용은 스토리지를 참고합니다.
크기 및 스토리지 제한#
관리자는 GitLab Self-Managed에 리포지터리 크기 제한을 설정할 수 있습니다. GitLab.com의 크기 제한은 사전에 정의되어 있습니다.
프로젝트가 크기 제한에 도달하면 푸시, 머지 리퀘스트 생성, LFS 객체 업로드 같은 일부 작업이 제한됩니다.
Git 히스토리 재작성 전 확인 사항#
Git 히스토리를 재작성하고 리포지터리에서 데이터를 제거하기 전에 다음 절의 내용을 반드시 고려해야 합니다.
로컬 클론 변경 필요#
리포지터리를 클론한 모든 사용자는 다음 중 하나를 수행해야 합니다:
- 로컬 사본을 삭제하고 리포지터리를 새로 클론합니다.
- 원격 변경 사항을 모두 페치하고 진행 중인 작업을 그 위에 리베이스합니다.
이 작업을 제대로 하지 않으면 로컬 변경 사항을 푸시하는 사용자가 삭제하려던 파일을 되살릴 수 있습니다.
실행 중인 파이프라인으로 인한 정리 실패#
정리 중에 파이프라인이 여전히 실행되고 있으면 파이프라인이 리포지터리와 상호작용하여 정리가 제대로 되지 않을 수 있습니다.
가비지 컬렉션 유예 기간#
GitLab은 30분의 유예 기간을 두고 Git 가비지 컬렉션을 실행합니다. 이 과정은 다음 두 조건을 모두 만족하는 객체를 정리합니다:
- 어떤 참조에서도 도달할 수 없습니다.
- 생성된 지 30분 이상 지났습니다.
제거하려는 데이터가 어떤 커밋에서든 도달할 수 있거나 생성된 지 30분이 지나지 않았다면 Git 가비지 컬렉션은 그 데이터를 제거하지 않습니다.
따라서 하우스키핑을 실행한 뒤 Prune unreachable objects를 선택하기까지 최소 30분을 기다려야 합니다.
포크된 프로젝트에서는 히스토리를 재작성할 수 없음#
내장 방식은 포크된 리포지터리에는 사용할 수 없습니다. GitLab 이 포크 전반에 객체를 저장하는 방식 때문에 Git 이 포크 사이에 공유되는 객체를 가비지 컬렉션으로 정리할 수 없습니다.
해결 방법: 프로젝트 아카이브#
정리 전에 프로젝트를 아카이브하면 리포지터리가 읽기 전용이 됩니다. 이렇게 하면 정리가 진행되는 동안 아무도 변경할 수 없습니다.
리포지터리를 아카이브하면 포크 관계도 제거됩니다. 따라서 데이터를 정리할 수 있습니다. 다만 데이터가 포크로 끌어올려진 경우에는 그쪽에서도 정리해야 합니다.
리포지터리 크기를 줄이는 방법#
리포지터리 크기를 줄이는 방법은 다음과 같습니다:
- 히스토리에서 파일 제거: Git 히스토리 전체에서 큰 파일을 제거합니다.
- 리포지터리 정리: 내부 Git 참조와 참조되지 않는 객체를 제거합니다.
- blob 제거: 민감하거나 기밀인 정보가 담긴 blob을 영구 삭제합니다.
리포지터리 크기를 줄이기 전에 리포지터리 전체 백업을 만들어야 합니다. 이 방법들은 되돌릴 수 없으며 프로젝트의 히스토리와 데이터에 영향을 줄 수 있습니다.
이 방법 중 무엇으로 리포지터리 크기를 줄이더라도 프로젝트 액세스를 차단할 필요는 없습니다. 사용자가 프로젝트에 계속 접근할 수 있는 상태에서 이 작업을 수행할 수 있습니다. 이 방법들에는 알려진 성능 영향이 없고 다운타임도 발생하지 않습니다. 다만 사용자에게 미칠 수 있는 영향을 최소화하려면 활동이 적은 시간대에 이 작업을 수행하는 편이 좋습니다.
리포지터리 히스토리에서 파일 제거#
Git 히스토리에서 큰 파일을 제거하려면 git filter-repo로 파일을 제거할 수 있습니다.
비밀번호나 키 같은 민감한 데이터를 제거할 때는 이 방법을 사용하지 않습니다.
대신 blob 제거 또는 텍스트 삭제 처리를 사용합니다.
이 과정은 다음과 같습니다:
- Git 히스토리 전체를 수정합니다.
- 열린 머지 리퀘스트에 영향을 줄 수 있습니다.
- 기존 파이프라인에 영향을 줄 수 있습니다.
- 로컬 리포지터리를 다시 클론해야 합니다.
- LFS 객체에는 영향을 주지 않습니다.
- 커밋 서명은 지정하지 않습니다.
- 되돌릴 수 없습니다.
파일 내용을 포함한 커밋 정보는 데이터베이스(DB)에 캐시되며, 리포지터리에서 제거된 뒤에도 계속 보일 수 있습니다.
리포지터리 정리#
리포지터리에서 내부 Git 참조와 참조되지 않는 객체를 제거할 때 이 방법을 사용합니다. 민감한 데이터를 제거할 때는 이 방법을 사용하지 않습니다. 민감한 데이터를 제거하려면 blob 제거 방법을 사용합니다.
이 과정은 다음과 같습니다:
git gc --prune=30.minutes.ago를 실행해 참조되지 않는 객체를 제거합니다.- 사용하지 않는 LFS 객체의 연결을 해제해 스토리지 공간을 확보합니다.
- 디스크상의 리포지터리 크기를 다시 계산합니다.
- 되돌릴 수 없습니다.
내부 Git 참조를 제거하면 연관된 머지 리퀘스트 커밋, 파이프라인, 변경 세부 정보를 사용할 수 없게 됩니다.
사전 요구 사항:
- 제거할 객체 목록이 필요합니다.
git filter-repo를 사용해commit-map파일에 객체 목록을 생성합니다.
리포지터리를 정리하려면 다음과 같이 합니다:
-
상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
-
Settings > Repository로 이동합니다.
-
Repository maintenance를 확장합니다.
-
제거할 객체 목록을 업로드합니다. 예를 들어
filter-repo디렉터리의commit-map파일을 업로드합니다.commit-map파일이 너무 크면 백그라운드 정리 프로세스가 시간을 초과해 실패할 수 있습니다. 그 결과 리포지터리 크기가 예상만큼 줄지 않습니다. 이를 해결하려면 파일을 나누어 여러 번에 걸쳐 업로드합니다.20000으로 시작해 필요에 따라 줄입니다. 예를 들면 다음과 같습니다:split -l 20000 filter-repo/commit-map filter-repo/commit-map- -
Start cleanup을 선택합니다.
정리가 끝나면 GitLab 이 다시 계산한 리포지터리 크기를 이메일로 알립니다.
리포지터리에서 데이터 제거#
리포지터리에서 민감하거나 기밀인 데이터를 제거하려면 다음 방법 중 하나를 사용합니다:
- 파일을 완전히 제거하려면 blob을 제거합니다.
- 파일은 유지하면서 기밀 텍스트만 대체 텍스트
***REMOVED***로 바꾸려면 텍스트를 삭제 처리합니다.
blob 제거#
히스토리
- GitLab 17.1에서
rewrite_history_ui라는 기능 플래그와 함께 도입됨. 기본적으로 비활성화됨. - GitLab 17.2에서 GitLab.com에 활성화됨.
- GitLab 17.3에서 GitLab Self-Managed 및 GitLab Dedicated에 활성화됨.
- GitLab 17.9에서 일반 제공됨. 기능 플래그
rewrite_history_ui제거됨.
Git 바이너리 대용량 객체(blob)는 메타데이터 없이 파일 내용을 저장합니다. 각 blob에는 리포지터리에 있는 파일의 특정 버전을 나타내는 고유한 SHA 해시가 있습니다.
민감하거나 기밀인 정보가 담긴 blob을 영구 삭제할 때 이 방법을 사용합니다.
이 과정은 다음과 같습니다:
- Git 히스토리를 재작성합니다.
- 커밋 서명을 제거합니다.
- 열린 머지 리퀘스트가 머지되지 않아 수동 리베이스가 필요할 수 있습니다.
- 이전 커밋 SHA를 참조하는 파이프라인이 깨질 수 있습니다.
- 이전 커밋 히스토리를 기준으로 하는 과거 태그와 브랜치에 영향을 줄 수 있습니다.
- 로컬 리포지터리를 다시 클론해야 합니다.
- 되돌릴 수 없습니다.
문자열을 대체 문자열 ***REMOVED***로 바꿀 수도 있습니다. 자세한 내용은
리포지터리에서 텍스트 삭제 처리를 참고합니다.
사전 요구 사항:
- 프로젝트에 대한 Owner 권한이 필요합니다.
- 제거할 객체 ID 목록이 필요합니다.
- 프로젝트가 다음에 해당하지 않아야 합니다:
- 공개 업스트림 프로젝트의 포크.
- 다운스트림 포크가 있는 공개 업스트림 프로젝트.
blob 제거가 성공하도록 하려면 작업 중에 리포지터리 액세스를 일시적으로 제한하는 방안을 고려합니다. blob 제거 중에 새 커밋이 푸시되면 작업이 실패할 수 있습니다.
리포지터리에서 blob을 제거하려면 다음과 같이 합니다:
- 상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
- 왼쪽 사이드바에서 Settings > Repository를 선택합니다.
- Repository maintenance를 확장합니다.
- Remove blobs를 선택합니다.
- 제거할 blob ID 목록을 한 줄에 하나씩 입력합니다.
- Remove blobs를 선택합니다.
- 확인 대화 상자에 프로젝트 경로를 입력합니다.
- Yes, remove blobs를 선택합니다.
- 계속하기 전에 blob 제거가 끝날 때까지 기다립니다:
- 이메일 알림이 활성화되어 있다면 리포지터리 히스토리 재작성이 완료되었다는 이메일을 받을 때까지 기다립니다.
- 이메일 알림이 활성화되어 있지 않다면 최소 5분을 기다립니다.
- 왼쪽 사이드바에서 Settings > General을 선택합니다.
- Advanced 섹션을 확장합니다.
- Run housekeeping을 선택합니다. 작업이 끝날 때까지 최소 30분을 기다립니다.
- 같은 Settings > General > Advanced 섹션에서 Prune unreachable objects를 선택합니다. 이 작업은 완료까지 약 5~10분이 걸립니다.
민감한 정보가 들어 있는 프로젝트가 포크된 경우, 하우스키핑 task가 이 과정을 끝내지 않은 채 성공할 수 있습니다. 하우스키핑은 포크된 데이터가 들어 있는 특수 객체 풀 리포지터리의 무결성을 유지해야 합니다. 도움이 필요하면 GitLab 지원에 문의합니다.
객체 ID 목록 가져오기#
blob을 제거하려면 제거할 객체 목록이 필요합니다.
이 ID를 얻으려면 ls-tree 명령이나 리포지터리 트리 목록 API 엔드포인트를 사용합니다.
다음 안내는 ls-tree 명령을 사용합니다.
사전 요구 사항:
- 리포지터리가 로컬 컴퓨터에 클론되어 있어야 합니다.
지정한 커밋이나 브랜치의 blob 목록을 크기순으로 가져오려면 다음과 같이 합니다:
-
터미널을 열고 리포지터리 디렉터리로 이동합니다.
-
다음 명령을 실행합니다:
git ls-tree -r -t --long --full-name | sort -nk 4출력 예시:
100644 blob 8150ee86f923548d376459b29afecbe8495514e9 133508 doc/howto/img/remote-development-new-workspace-button.png 100644 blob cde4360b3d3ee4f4c04c998d43cfaaf586f09740 214231 doc/howto/img/dependency_proxy_macos_config_new.png 100644 blob 2ad0e839a709e73a6174e78321e87021b20be445 216452 doc/howto/img/gdk-in-gitpod.jpg 100644 blob 115dd03fc0828a9011f012abbc58746f7c587a05 242304 doc/howto/img/gitpod-button-repository.jpg 100644 blob c41ebb321a6a99f68ee6c353dd0ed29f52c1dc80 491158 doc/howto/img/dependency_proxy_macos_config.png출력의 세 번째 칼럼이 blob의 객체 ID 입니다. 예:
8150ee86f923548d376459b29afecbe8495514e9.
리포지터리에서 텍스트 삭제 처리#
히스토리
- GitLab 17.1에서
rewrite_history_ui라는 기능 플래그와 함께 도입됨. 기본적으로 비활성화됨. GitLab 팀원은 다음 비공개 이슈에서 자세한 내용을 볼 수 있음:https://gitlab.com/gitlab-org/gitlab/-/issues/450701. - GitLab 17.2에서 비공개 이슈
https://gitlab.com/gitlab-org/gitlab/-/issues/462999로 GitLab.com에 활성화됨. - GitLab 17.3에서 비공개 이슈
https://gitlab.com/gitlab-org/gitlab/-/issues/462999로 GitLab Self-Managed 및 GitLab Dedicated에 활성화됨. - GitLab 17.9에서 비공개 이슈
https://gitlab.com/gitlab-org/gitlab/-/issues/472018로 일반 제공됨. 기능 플래그rewrite_history_ui제거됨.
실수로 커밋한 민감하거나 기밀인 정보를 영구 삭제해, 리포지터리 히스토리에서
더 이상 접근할 수 없게 합니다.
지정한 문자열 목록을 ***REMOVED***로 바꿉니다.
이 작업은 되돌릴 수 없습니다. 히스토리를 재작성하고 하우스키핑을 실행하면 변경은 영구적입니다.
GitLab에서 파일을 삭제 처리하면 노출된 시크릿은 제거되지만 다음과 같은 영향도 있습니다:
- Git 히스토리를 재작성합니다. 이전 커밋 히스토리를 기준으로 하는 과거 태그와 브랜치가 제대로 동작하지 않을 수 있습니다.
- 파괴적입니다. 기존 로컬 클론은 갱신된 리포지터리와 호환되지 않으므로 다시 클론해야 합니다.
- 삭제 처리로 내용이 바뀌므로 커밋 해시가 갱신됩니다.
- 재작성 과정에서 커밋 서명이 제거됩니다.
- 커밋 해시에 의존하는 다음 기능이 깨집니다:
- 열린 머지 리퀘스트. 열린 머지 리퀘스트가 머지되지 않아 수동 리베이스가 필요할 수 있습니다.
- 이전 커밋으로 연결되는 링크. 404 오류가 발생합니다.
- 이전 커밋 SHA를 참조하는 파이프라인이 깨져 재구성이 필요할 수 있습니다.
리포지터리 무결성을 위해서는 다음 방법을 권장합니다:
- 노출된 시크릿을 폐기하거나 교체합니다.
- GitLab의 시크릿 탐지 기능을 도입합니다.
이 접근 방식은 다음과 같은 효과가 있습니다:
- 향후 시크릿 유출을 선제적으로 방지합니다.
- 보안 규정을 준수하면서 Git 히스토리를 유지합니다.
자세한 내용은 시크릿 푸시 보호를 참고합니다.
리포지터리에서 특정 파일을 완전히 삭제하려면 blob 제거를 참고합니다.
사전 요구 사항:
- 프로젝트에 대한 Owner 권한이 필요합니다.
리포지터리에서 텍스트를 삭제 처리하려면 다음과 같이 합니다:
- 상단 바에서 Search or go to를 선택하고 프로젝트를 찾습니다.
- 왼쪽 사이드바에서 Settings > Repository를 선택합니다.
- Repository maintenance를 확장합니다.
- Redact text를 선택합니다.
- 드로어에 삭제 처리할 텍스트를 입력합니다. 정규식과 글로브 패턴을 사용할 수 있습니다.
- Redact matching strings를 선택합니다.
- 확인 대화 상자에 프로젝트 경로를 입력합니다.
- Yes, redact matching strings를 선택합니다.
- 왼쪽 사이드바에서 Settings > General을 선택합니다.
- Advanced를 확장합니다.
- Run housekeeping을 선택합니다. 작업이 끝날 때까지 최소 30분을 기다립니다.
- 같은 Settings > General > Advanced 섹션에서 Prune unreachable objects를 선택합니다. 이 작업은 완료까지 약 5~10분이 걸립니다.
민감한 정보가 들어 있는 프로젝트가 포크된 경우, 하우스키핑 task가 포크된 데이터가 들어 있는 특수 객체 풀 리포지터리의 무결성을 유지하기 위해 이 삭제 처리 과정을 끝내지 못할 수 있습니다. 도움이 필요하면 GitLab 지원에 문의합니다.
문제 해결#
이 절에는 발생할 수 있는 문제의 해결 방법이 있습니다.
GUI에 잘못된 리포지터리 통계 표시#
GitLab 인터페이스에 표시되는 리포지터리 크기나 커밋 수가 내보낸 .tar.gz 또는
로컬 리포지터리와 다르면 다음과 같이 합니다:
-
GitLab 관리자에게 Rails 콘솔로 강제 업데이트를 요청합니다.
-
관리자는 다음 명령을 실행합니다:
p = Project.find_by_full_path('<namespace>/<project>') p.statistics.refresh! -
프로젝트 통계를 지우고 재계산을 트리거하려면 다음과 같이 합니다:
p.repository.expire_all_method_caches UpdateProjectStatisticsWorker.perform_async(p.id, ["commit_count","repository_size","storage_size","lfs_objects_size","container_registry_size"]) -
전체 아티팩트 스토리지 공간을 확인하려면 다음과 같이 합니다:
builds_with_artifacts = p.builds.with_downloadable_artifacts.all artifact_storage = 0 builds_with_artifacts.find_each do |build| artifact_storage += build.artifacts_size end puts "#{artifact_storage} bytes"
정리 후 공간이 확보되지 않음#
리포지터리 정리를 끝냈는데도 스토리지 사용량이 그대로라면 다음을 확인합니다:
- 도달할 수 없는 객체는 2주의 유예 기간 동안 리포지터리에 남아 있습니다.
- 이 객체들은 내보내기에는 포함되지 않지만 파일 시스템 공간은 계속 차지합니다.
- 2주가 지나면 이 객체들은 자동으로 정리되며, 그때 스토리지 사용량 통계가 갱신됩니다.
- 이 과정을 앞당기려면 관리자에게 'Prune Unreachable Objects' 하우스키핑 task 실행을 요청합니다.
blob 이 제거되지 않음#
blob 이 정상적으로 제거되면 GitLab은 프로젝트 감사 로그에 항목을 추가하고 작업을 시작한 사용자에게 이메일 알림을 보냅니다.
blob 제거가 실패하면 GitLab은 작업을 시작한 사용자에게 제목이
<project_name> | Project history rewrite failure 인 이메일 알림을 보냅니다. 이메일 본문에는 전체 오류 메시지가 담겨 있습니다.
발생할 수 있는 오류와 해결 방법은 다음과 같습니다:
validating object ID: invalid object ID: 객체 ID 목록에 구문 오류나 잘못된 객체 ID가 있습니다. 해결 방법은 다음과 같습니다:- 객체 ID 목록을 다시 생성합니다.
- blob 제거 단계를 다시 수행합니다.
source repository checksum altered: blob 제거 중에 누군가 커밋을 푸시했을 때 발생합니다. 해결 방법은 다음과 같습니다:- 리포지터리로의 모든 푸시를 일시적으로 차단합니다.
- blob 제거 단계를 다시 수행합니다.
- 작업이 성공적으로 끝난 뒤 푸시를 다시 허용합니다.
리포지터리 크기 제한 도달#
리포지터리 크기 제한에 도달했다면 다음과 같이 합니다:
- 데이터를 일부 제거하고 새 커밋을 만들어 봅니다.
- 그래도 되지 않으면 일부 blob을 Git LFS로 옮기거나 히스토리에서 오래된 의존성 업데이트를 제거하는 방안을 고려합니다.
- 그래도 변경 사항을 푸시할 수 없다면 GitLab 관리자에게 프로젝트의 제한을 일시적으로 늘려 달라고 요청합니다.
- 최후의 수단으로 새 프로젝트를 만들어 데이터를 마이그레이션합니다.
새 커밋에서 파일을 삭제해도 이전 커밋과 blob 이 남아 있으므로 리포지터리 크기가 곧바로 줄지는 않습니다.
크기를 실제로 줄이려면 git filter-repo 같은 도구로 히스토리를 재작성해야 합니다.