Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
implemented |
@jdrpereira
|
@glopezfernandez
|
@trizzi
@hswimelar
| devops package | 2020-09-29 |
컨테이너 레지스트리 메타데이터 데이터베이스
GitLab 컨테이너 레지스트리의 사용
컨테이너 레지스트리가 GitLab에 통합되면 모든 GitLab 프로젝트마다 도커 이미지를 저장할 공간을 갖게 됩니다. 레지스트리를 사용하여 도커 클라이언트, CI/CD 또는 GitLab API를 사용하여 이미지를 빌드, 푸시 및 공유할 수 있습니다.
GitLab.com에서 매일 15만~20만 개의 이미지가 레지스트리에 푸시되며, 약 70만 개의 API 이벤트가 생성됩니다. 또한 몇몇 고객이 다른 레지스트리 공급업체를 사용하더라도, 96% 이상의 인스턴스가 GitLab 컨테이너 레지스트리를 사용하고 있다는 점에 유의해야 합니다.
GitLab.com과 GitLab 고객들에게 컨테이너 레지스트리는 소프트웨어를 빌드하고 배포하는 데 중요한 컴포넌트입니다.
현재 아키텍처
컨테이너 레지스트리는 Go 애플리케이션입니다. 이미지와 메타데이터가 저장되는 스토리지 백엔드만 의존합니다.
클라이언트 애플리케이션(예: GitLab Rails 및 Docker CLI)은 HTTP API를 통해 컨테이너 레지스트리와 상호 작용합니다. 가장 일반적인 작업은 레지스트리로 이미지를 푸시하고 풀링하는 것으로, 특정한 순서로 HTTP 요청의 시리즈가 필요합니다. 이러한 작업에 대한 요청 플로우는 요청 플로우에서 자세히 설명되어 있습니다.
레지스트리는 Google Cloud Storage (GCS)를 포함하여 여러 스토리지 백엔드를 지원하며, GitLab.com 레지스트리에는 GCS가 사용됩니다. 스토리지 백엔드에서 이미지는 블롭으로 저장되어 중복 처리되며, 리포지터리 전체에서 공유됩니다. 그런 다음 이러한 이미지는 각각의 리포지터리에 대해 링크되어 (심볼릭 링크처럼) 중앙 저장 위치에 액세스할 수 있도록 제공됩니다.
리포지터리의 이름, 계층 구조, 이미지 매니페스트 및 태그도 폴더와 파일의 중첩 구조로 표현되어 스토리지 백엔드에 저장됩니다. 이 비디오를 통해 레지스트리 리포지터리 구조를 실제로 확인할 수 있습니다.
클라이언트
컨테이너 레지스트리에는 두 가지 주요 클라이언트가 있습니다: GitLab Rails 애플리케이션 및 Docker 클라이언트/CLI.
Docker
Docker 클라이언트(docker
CLI)는 주로 login, push, 및 pull 명령을 사용하여 GitLab 컨테이너 레지스트리와 상호 작용합니다.
로그인 및 인증
GitLab Rails은 GitLab 컨테이너 레지스트리의 기본 토큰 기반 인증 제공자입니다.
레지스트리가 인증되지 않은 Docker 클라이언트로부터의 요청을 받으면, 401 Unauthorized
응답을 하고 클라이언트에게 GitLab Rails API에서 토큰을 얻도록 안내합니다. 그런 다음 Docker 클라이언트는 Bearer 토큰을 요청하고 모든 요청의 Authorization
헤더에 임베드합니다. 레지스트리는 제공된 토큰을 기반으로 사용자가 해당 요청을 수행할 수 있는지 여부를 결정하는 것입니다.
자세한 내용은 Docker 설명서를 참조하세요.
푸시 및 풀
푸시 및 풀 명령은 이미지를 업로드하고 다운로드하는 데 사용되며, 정확히는 매니페스트와 블롭을 업로드하고 다운로드하는 것입니다. 푸시/풀 플로우에 대한 자세한 내용은 문서에 설명되어 있습니다.
GitLab Rails
GitLab Rails은 레지스트리와 HTTP API를 통해 상호 작용하고 웹훅 알림을 사용합니다.
GitLab Rails에서 레지스트리로
레지스트리의 단일 진입점은 HTTP API입니다. GitLab Rails은 모든 작업을 수행하기 위해 API를 호출하는데, 이는 다음과 같은 작업을 포함합니다.
작업 | UI | 배경 작업 | 관찰 사항 |
---|---|---|---|
API 버전 확인 | 예 | 예 | Docker Distribution V2 API를 지원하는지 전역적으로 확인하고, GitLab Rails가 GitLab 컨테이너 레지스트리 또는 서드파티 레지스트리와 통신하는지 식별하는 데 사용됨(후자에서만 사용 가능한 기능을 토글하는 데 사용됨) |
리포지터리 태그 디렉터리 | 예 | 예 | UI에서 태그를 표시하고 보기 위한 목적으로 사용됨. 정리 정책 및 Geo 복제에서 백그라운드로 태그를 나열하는 데 사용됨 |
매니페스트의 존재 여부 확인 | 예 | 아니오 | 태그별 매니페스트의 다이제스트를 가져오는 데 사용됨. 그런 다음 이것을 사용하여 매니페스트를 가져와 UI에서 태그 세부 정보를 표시함 |
매니페스트 받기 | 예 | 아니오 | UI에서 이미지 크기와 매니페스트 다이제스트를 표시하는 데 사용됨 |
블롭 받기 | 예 | 아니오 | UI에서 구성 다이제스트와 생성 날짜를 표시하는 데 사용됨 |
태그 삭제 | 예 | 예 | UI 및 백그라운드(정리 정책)에서 태그를 삭제하는 데 사용됨 |
이러한 요청을 전송하기 전에 GitLab Rails에서 유효한 인증 토큰이 생성되어 모든 요청에 임베드됩니다.
레지스트리부터 GitLab Rails까지
레지스트리는 웹훅 알림을 지원하여 이미지 푸시와 같은 이벤트 발생 시 외부 응용프로그램에 알립니다.
GitLab의 경우 레지스트리는 현재 이미지 푸시 이벤트에 대한 알림을 GitLab Rails API로 전달하도록 구성되어 있습니다. 이러한 알림은 현재 Snowplow 메트릭 및 Geo 복제에 사용됩니다.
도전과제
가비지 컬렉션
컨테이너 레지스트리는 오프라인 마크 및 스윕 가비지 컬렉션(GC) 알고리즘에 의존합니다. 이를 실행하기 위해 레지스트리는 종료하거나 읽기 전용으로 설정되어야 하며, 이러한 상태는 GC 실행 동안 유지되어야 합니다.
마크 단계 중에 레지스트리는 모든 리포지터리를 분석하여 각 리포지터리에서 참조된 구성, 레이어 및 매니페스트의 디렉터리을 작성합니다. 그런 다음 레지스트리는 모든 기존 구성, 레이어 및 매니페스트(중앙에 저장된)를 나열하고 어떤 리포지터리에서도 참조되지 않는 것들의 디렉터리을 얻습니다. 이는 삭제할 수 있는 블롭의 디렉터리입니다.
마크 단계의 결과를 가지고 레지스트리는 스윕 단계를 시작하는데, 여기서 삭제할 수 있는 블롭의 디렉터리을 모두 확인하고 스토리지 백엔드에서 하나씩 삭제합니다.
대규모 레지스트리에 대해 이 작업은 완료하는 데 여러 시간/일이 걸릴 수 있으며, 레지스트리는 읽기 전용 모드로 유지되어야 합니다. 이는 GitLab.com과 같은 엄격한 가용성 요구 사항이 있는 플랫폼에는 적합하지 않습니다.
이 제한 사항은 상류 도커 레지스트리 문서에서도 설명되어 있습니다.
성능
현재 아키텍처 및 (가능한 원격) 스토리지 백엔드에 대한 리포지터리 및 이미지 메타데이터의 의존성으로 인해, 리포지터리 또는 태그를 나열하는 등 가장 기본적인 작업조차도 금지적으로 느려질 수 있으며, 레지스트리가 커질수록 상황은 악화됩니다.
예를 들어, 어떤 리포지터리가 존재하는지 확인하려면 레지스트리는 스토리지 백엔드의 모든 폴더를 훑어야 하고 그 안에 존재하는 리포지터리를 식별해야 합니다. 존재하는 모든 폴더를 방문한 후에야 레지스트리가 클라이언트에게 리포지터리 디렉터리을 반환할 수 있습니다. 원격 스토리지 백엔드(GCS 또는 S3와 같은)를 사용하는 경우 성능은 더 나빠지는데, 각 폴더 방문마다 여러 개의 HTTP 요청이 필요하여 그 내용을 나열하고 검사해야 합니다.
일관성
S3와 같은 일부 스토리지 백엔드는 일관성 도입만 제공할 수 있습니다. 예를 들어 삭제한 후에도 블롭을 읽을 수 있는 경우가 짧은 시간 동안 발생할 수 있습니다. 이러한 일관성은 온라인 가비지 수집과 결합될 때 문제가 발생할 수 있는데, API 수준의 읽기 요청은 삭제된 블롭에 대해 계속 성공할 수 있습니다.
통찰력
위에서 강조한 이유로 현재 레지스트리에서 리포지터리가 사용하는 공간의 양, 어느 리포지터리가 가장 많은 공간을 사용하는지, 어떤 것이 더 활발한지, 각 이미지 또는 태그의 상세한 푸시/풀 메트릭 등 유용한 정보를 추출하는 것이 현재는 불가능합니다. 이러한 통찰력 및 메트릭에 액세스할 수 없는 것은 제품 전략에 대한 판단을 내리는 능력을 크게 약화시킵니다.
추가 기능
메타데이터 제한으로 인해 HTTP API에 대한 페이지네이션, 필터링 및 정렬과 같은 유용한 기능들을 구현하는 것은 현재 불가능하며, 도커 및 Helm 차트 이미지를 구분하는 기능과 같은 고급 기능들을 포함한 더 많은 고급 기능들을 구현하는 것도 불가능합니다.
이러한 모든 제약으로 인해 우리는 새로운 기능의 개발을 중단하기로 결정했습니다 외에는 모든 이러한 기본적인 제약을 극복하기 위한 해결책이 마련될 때까지.
새로운 아키텍처
위에서 설명한 모든 도전과제를 극복하기 위해 우리는 레지스트리 메타데이터(블롭, 리포지터리 및 각각의 매니페스트/레이어이 참조/링크)를 PostgreSQL 데이터베이스로 마이그레이션하는 작업을 시작했습니다.
새 아키텍처의 궁극적인 목표는 온라인 가비지 수집(&2313)을 가능하게 하는 것인데, 데이터베이스가 마련되면 메타데이터 제약으로 막힌 모든 기능들을 구현할 수도 있게 될 것입니다. 기존 API의 성능 역시 크게 향상될 것입니다.
데이터베이스가 마련되면 레지스트리는 더 이상 스토리지 백엔드를 사용하여 메타데이터를 쓰거나 읽지 않을 것입니다. 대신 메타데이터는 PostgreSQL 데이터베이스에 저장되고 조작될 것입니다. 스토리지 백엔드는 이후 블롭을 업로드하고 다운로드하는 데에만 사용될 것입니다.
GitLab Rails 및 Docker 클라이언트를 포함한 레지스트리와 그 클라이언트 간의 상호 작용은 현재 아키텍처 섹션에 문서화된 대로 변경되지 않을 것입니다. 아키텍처 변경과 데이터베이스는 내부적인 것뿐입니다. 레지스트리 HTTP API 및 웹훅 알림도 그대로 유지될 것입니다.
데이터베이스
GitLab Go 표준 및 스타일 지침을 준수하기 위해 데이터베이스 관리에는 ORM이 사용되지 않으며 Go 표준 라이브러리의 database/sql
패키지, PostgreSQL 드라이버(lib/pq
) 및 TCP 연결 풀을 통한 원시 SQL 쿼리만 사용됩니다.
레지스트리 데이터베이스의 설계 및 개발은 GitLab 데이터베이스 지침을 준수합니다. Go 애플리케이션이므로 데이터베이스 지원을 위한 필수 도구들(예: 데이터베이스 마이그레이션 실행)을 개발해야 할 것입니다.
온라인 및 배포 후 마이그레이션 실행은 이미 레지스트리 CLI에서 지원되며 문서에 설명되어 있습니다.
파티션
레지스트리 데이터베이스는 시작부터 파티셔닝되어 더 나은 성능(적용할 데이터 양을 제한하고 병렬 실행을 활성화하여), 더 쉬운 유지보수(테이블 및 인덱스를 작은 단위로 분할함으로써) 및 고가용성(파티션 독립성으로)을 달성할 것입니다. 데이터베이스를 시작부터 파티션하여 필요한 경우 나중에 샤딩 구현을 용이하게 할 수도 있습니다.
블롭은 리포지터리 전체에서 공유되지만 매니페스트와 태그 메타데이터는 리포지터리별로 범위가 지정됩니다. 이는 API 수준에서도 나타나며, 모든 쓰기 및 읽기 요청(리포지터리 나열을 제외한)이 리포지터리별로 범위가 지정되며 해당 네임스페이스가 요청 URI의 일부가 됩니다. 따라서 액세스 패턴을 식별한 후, 매니페스트와 태그를 리포지터리별로 파티션하고 블롭을 해시 값에 의해 파티션하여 조회가 항상 최적의 성능으로 수행되도록 하기로 결정했습니다. 파티션된 스키마의 초기 버전은 Merge Request에 문서화되었습니다.
GitLab.com
규모, 성능 및 격리 관련 우려로 인해 GitLab.com의 레지스트리 데이터베이스는 별도로 전용 PostgreSQL 클러스터에 위치할 것입니다. 추가 컨텍스트는 #93 및 GitLab-com/gl-infra/reliability#10109에서 확인할 수 있습니다.
아래 다이어그램은 데이터베이스 클러스터의 아키텍처를 설명합니다:
예상 요구율 및 크기
GitLab.com 데이터베이스의 요구율 및 크기는 dev.gitlab.org
레지스트리를 기반으로 추정되었으며 연결된 이슈에서 확인할 수 있습니다.
Self-managed 인스턴스
기본적으로 Self-managed 인스턴스의 경우 레지스트리는 GitLab 데이터베이스와 동일한 PostgreSQL 인스턴스/클러스터 내에서 별도의 논리적 데이터베이스를 가질 것입니다. 그러나 필요한 경우 레지스트리를 별도의 인스턴스/클러스터로 구성할 수도 있을 것입니다.
PostgreSQL
최초 데이터베이스 스키마를 논의하는 동안 주로 다른 데이터베이스 엔진 대신 PostgreSQL을 선택하는 결정을 내렸는데, 주된 이유는 다음과 같습니다:
- ACID(원자성, 일관성, 고립성, 지속성) 보장과 파티션 포함을 포함한 필요한 모든 기능을 제공합니다.
- 이미 GitLab에서 사용되고 있어 필요한 경험과 도구가 이미 구축되어 있습니다.
- Self-managed 고객에게 이미 보유한 GitLab용 PostgreSQL 인스턴스 내에 레지스트리 데이터베이스를 호스팅할 수 있는 기회를 제공하고자 합니다.
버전 12
PostgreSQL 12는 버전 12에서 파티션에 대한 중요한 개선 사항을 도입했는데, 중요한 개선 사항은 다음과 같습니다:
- 이제 외래 키가 파티션된 테이블을 참조할 수 있습니다. 이것은 일관성과 무결성을 보장하는 것뿐만 아니라 데이터베이스 수준에서의 카스케이딩 삭제를 가능케 하기 위한 필수 조건입니다.
- 파티션 수가 많은 테이블에 대한 삽입, 선택 및 업데이트의 주요 성능 개선으로 덜한 잠금 및 대규모 파티션에 대한 일관된 성능을 제공합니다 (벤치마킹).
- 많은 파티션을 가진 테이블에 대한 계획 알고리즘에 대한 주요 개선으로 일부 테스트에서 최대 10,000배의 가속화 결과도 나타났습니다 (출처).
- 기존 테이블에 새로운 파티션을 연결하기 위해 이제 전체 테이블을 잠그는 것이 필요하지 않습니다.
-
COPY
는 이제 한 번에 한 행을 삽입하는 대신 대량 삽입을 사용합니다.
이러한 기능 및 성능 개선을 활용하기 위해 시작부터 PostgreSQL 12를 사용해야 합니다. GitLab 14.0 이상에서는 Self-managed 인스턴스에 PostgreSQL 12가 함께 제공됩니다. PostgreSQL 12로 업그레이드할 수 없는 고객에게는 두 가지 옵션이 있습니다:
- 관리자는 매뉴얼으로 PostgreSQL 12 데이터베이스를 프로비저닝하고 구성할 수 있습니다. 새 레지스트리 및 해당 메타데이터 데이터베이스가 제공하는 기능을 활용할 수 있습니다.
- 온라인 가비지 수집이 문제가 되지 않거나 별도의 데이터베이스를 프로비저닝하는 것이 불가능한 경우 현재 레지스트리를 사용하되 데이터베이스 없이 계속 사용할 수 있습니다. GitLab은 보안 백포트와 버그 수정을 지원합니다.
온라인 가비지 수집을 제외하고도 메타데이터 데이터베이스의 가용성은 GitLab 컨테이너 레지스트리에 대한 많은 요청된 기능들의 구현을 허용합니다. 이러한 기능은 새 버전을 사용하고 메타데이터 데이터베이스를 백업하는 인스턴스에서만 사용할 수 있습니다.
가용성
인증 서비스와 블롭 리포지터리 백엔드를 제외하고 새 아키텍처에서 레지스트리는 데이터베이스에 대한 또 다른 의존성을 얻습니다. 레지스트리는 의존성처럼 신뢰할 수밖에 없기 때문에 데이터베이스 배포는 고가용성으로 계획되어야 합니다. 점진적인 마이그레이션 접근 방식은 고가용성 환경에서의 구현 및 리소스 제한을 식별하고 완화하는 데 도움이 될 것입니다.
HTTP API
이것은 모든 레지스트리 HTTP API 작업 디렉터리이며 그들이 리포지터리 백엔드 및 새 데이터베이스를 어떻게 의존하는지에 대한 내용입니다. 요청 처리 시 필요한 의존성이 어떤 것들이 없을 경우 레지스트리는 오류 응답을 반환합니다.
작업 | 방법 | 경로 | 데이터베이스 필요 | 리포지터리 필요 | GitLab Rails에서 사용 * |
---|---|---|---|---|---|
API 버전 확인 | GET
| /v2/
| 아니오 | 아니오 | 예 |
리포지터리 나열 | GET
| /v2/_catalog
| 예 | 아니오 | 아니오 |
리포지터리 태그 나열 | GET
| /v2/<name>/tags/list
| 예 | 아니오 | 예 |
태그 삭제 | DELETE
| /v2/<name>/manifests/<reference>
| 예 | 아니오 | 예 |
매니페스트 존재 여부 확인 | HEAD
| /v2/<name>/manifests/<reference>
| 예 | 아니오 | 예 |
매니페스트 가져오기 | GET
| /v2/<name>/manifests/<reference>
| 예 | 아니오 | 예 |
매니페스트 푸시 | PUT
| /v2/<name>/manifests/<reference>
| 예 | 아니오 | 아니오 |
매니페스트 삭제 | DELETE
| /v2/<name>/manifests/<reference>
| 예 | 아니오 | 아니오 |
블롭 존재 여부 확인 | HEAD
| /v2/<name>/blobs/<digest>
| 예 | 아니오 | 아니오 |
블롭 가져오기 | GET
| /v2/<name>/blobs/<digest>
| 예 | 예 | 예 |
블롭 삭제 | DELETE
| /v2/<name>/blobs/<digest>
| 예 | 아니오 | 아니오 |
블롭 업로드 시작 | POST
| /v2/<name>/blobs/uploads/
| 예 | 예 | 아니오 |
블롭 업로드 상태 확인 | GET
| /v2/<name>/blobs/uploads/<uuid>
| 예 | 예 | 아니오 |
블롭 청크 푸시 | PATCH
| /v2/<name>/blobs/uploads/<uuid>
| 예 | 예 | 아니오 |
블롭 업로드 완료 | PUT
| /v2/<name>/blobs/uploads/<uuid>
| 예 | 예 | 아니오 |
블롭 업로드 취소 | DELETE
| /v2/<name>/blobs/uploads/<uuid>
| 예 | 예 | 아니오 |
*
GitLab Rails에서 레지스트리까지의 상호 작용 디렉터리을 참조하여 왜 및 어떻게를 알아보십시오.
장애 시나리오
데이터베이스 추가로, 잠재적인 장애 시나리오를 강조하고, 레지스트리가 이러한 상황에서 어떻게 동작할 것으로 예상되는지, 그리고 레지스트리 가용성과 기능성에 미치는 영향을 설명하는 것이 필수적입니다.
데이터베이스 장애 조치
데이터베이스에 연결을 시도할 때 거부된 연결이나 시간 초과가 발생하는 경우(장애 조치 시 발생할 수 있는 상황), 레지스트리는 먼저 끊어진 연결을 버리고 즉시 풀에서 새 연결을 시도할 것입니다.
이 시나리오에서 응용 프로그램은 패닉 상태에 빠지지 않습니다. 각 요청에 대해 새 연결을 시도할 것입니다. 실패한 경우 클라이언트에게 HTTP 503 Service Unavailable
오류를 반환하고, 해당 오류는 로그에 기록되어 Sentry에 보고됩니다. 재시도 간격은 없습니다. 레지스트리는 데이터베이스 액세스가 필요한 다른 요청을 받았을 때에만 새 연결을 시도할 것입니다.
또한 TCP 헬스 체커를 사용하여 데이터베이스 서버의 헬스를 주기적으로 확인하도록 레지스트리를 구성하는 것도 가능합니다. 이때 구성 가능한 간격과 임계값이 있습니다(문서). 상태 체크에서 실패하는 경우, 들어오는 요청은 HTTP 503 Service Unavailable
오류로 중단될 것입니다.
데이터베이스 서버가 다시 사용 가능한 경우, 레지스트리는 다음 들어오는 요청에서 새 연결을 원활하게 재연결하여 사람의 개입 없이 전체 API 기능을 복원할 것입니다.
예상된 레지스트리 동작은 통합 테스트로 확인될 것이며, 이를 위해 레지스트리와 데이터베이스 서버 간의 프로그래밍 가능한 TCP 프록시를 사용하여 장애 조치 시나리오를 시뮬레이션할 것입니다.
연결 풀 포화
특정 요청을 처리하기 위해 풀에서 연결을 가져올 수 없는 경우, 레지스트리는 타임아웃되고 클라이언트에게 HTTP 500 Internal Server Error
오류를 반환하고 해당 오류를 Sentry에 보고할 것입니다. 이러한 문제는 풀이 과다하게 사용되고 있는 이유를 조사하기 위해 개발 담당자에 의한 강화가 필요합니다. 미리 구성된 풀 크기에 대한 부하가 너무 많거나 연결이 너무 오래 유지되고 있을 수 있습니다.
응용 프로그램이 오류를 반환하기 전에 포화 상태에 대응하기 위해 Prometheus 메트릭스를 사용하여 경고를 생성해야 합니다. 새 레지스트리 노드에 제한적이고 점진적이며 통제된 노출을 갖게 될 GitLab.com 레지스트리의 점진적 이관 중에 이러한 시나리오에 특별한 주의를 기울여야 합니다. 이 프로세스 중에 우리는 사용 패턴을 식별하고 메트릭스를 관찰하며 부하가 증가함에 따라 인프라 및 응용 프로그램 설정을 세밀하게 조정할 수 있을 것입니다. 필요한 경우 영향을 제한하기 위해 속도 제한 알고리즘을 적용할 수 있습니다. 결정은 지나치게 제한적인 조치와 조기 최적화를 피하기 위해 실제 데이터를 기반으로 할 것입니다.
예상된 레지스트리 동작은 풀 크기를 조정하고 API에 대해 여러 동시 요청을 스폰하고, 풀에 압력을 가하고 마침내 풀의 용량을 고갈시키는 통합 테스트로 확인될 것입니다.
지연
설정된 연결에서 지연이 과도하면 일반적인 상황에서 응용 프로그램 오류나 네트워크 타임아웃을 발생시키지 않을 수 있기 때문에, 이를 감지하고 디버그하는 것은 어렵습니다.
그 이유로, HTTP API 요청을 서빙하는 데 사용된 데이터베이스 쿼리의 지속 시간이 메트릭을 사용하여 장비화되어야 합니다. 이를 통해 비정상적인 변동 사항을 감지하고 이에 따라 경고를 트리거하여 과도한 지연이 타임아웃이나 서비스 가용성이 되기 전에 조치를 취할 수 있어야 합니다.
예상된 레지스트리 동작은 증가하는 지연 시나리오를 시뮬레이션하기 위해, 레지스트리와 데이터베이스 서버 간에 프로그래밍 가능한 TCP 프록시를 사용하여 통합 테스트로 확인될 것입니다.
문제가 있는 마이그레이션
비정상적인 네트워크 및 시스템 조건 외에도, 문제가 있는 마이그레이션 및 데이터 오류는 데이터베이스 가용성 및 레지스트리 가용성에 영향을 줄 수 있습니다.
데이터베이스 마이그레이션은 GitLab Rails에서 사용된 개발 최상의 실천 방법을 준수할 것이며, 오직 Rails 특정 메서드 및 도구가 아닌 SQL 문으로 표현되는 마이그레이션과 같은 Go 응용 프로그램을 위해 사용될 것입니다. 그러나 모든 변경 사항은 데이터베이스 팀의 검토와 승인이 필요할 것입니다.
데이터베이스 마이그레이션은 멱등적이며, 필요한 경우 가드 절을 사용할 것입니다. 또한, 앞으로 호환성이 보장될 것입니다. 클러스터 환경에서 버전 N
을 실행하는 노드는 데이터베이스 스키마가 버전 N
+1인 경우 문제가 발생하지 않을 것입니다.
가시성
시스템에 컴포넌트를 추가하는 것은 새로운 레지스트리와 관련된 행동 및 의존성에 대한 적절한 가시성을 확보하는 것이 더욱 중요하게 만듭니다. 새 메타데이터 데이터베이스를 기반으로 한 새 레지스트리를 롤아웃하기 전에 필요한 모든 도구가 제대로 갖춰졌는지 보장할 필요가 있습니다.
이를 위해 Sentry를 사용한 오류 보고, 개선된 구조화된 로깅 및 개선된 HTTP 메트릭이 이미 구현되어 배포되었습니다. 현재 GitLab.com 롤아웃이 진행 중입니다.
또한 프로메테우스 메트릭은 데이터베이스 연결 풀에 대한 세부 정보와 함께 확장될 것입니다. 이러한 메트릭은 기존의 HTTP API, 배포 및 저장 메트릭과 함께 레지스트리 그라파나 대시보드에 추가될 것입니다. 레지스트리용 데이터베이스 클러스터 메트릭 및 경고도 포함될 것입니다.
이러한 리소스들은 레지스트리의 성능과 동작에 대한 충분한 수준의 통찰력을 제공해야 합니다.
새로운 기능과 팽단 변경 사항
타사 컨테이너 레지스트리
GitLab은 기본적으로 GitLab 컨테이너 레지스트리와 함께 제공되지만, Docker Distribution V2 Specification를 준수하는 한 타사 레지스트리와도 호환됩니다. 이는 이제 Open Container Initiative (OCI) Image Specification에 의해 대체되었습니다.
지금까지 새로운 기능을 추가할 때 타사 레지스트리와의 완전한 호환성을 유지하기 위해 노력해왔습니다. 예를 들어, 12.8에서 우리는 단일 태그를 삭제하는 새로운 태그 삭제 기능을 도입했습니다. 이 기능은 Docker 또는 OCI 명세의 일부가 아니므로 타사 레지스트리와의 호환성을 유지하기 위해 기존 동작을 대안 옵션으로 유지하고 있습니다.
그러나 이는 앞으로 변경될 것입니다. 온라인 가비지 수집 외에도 도전과제에서 설명한 대로, 메타데이터 데이터베이스는 중/장기적으로 GitLab 컨테이너 레지스트리를 위한 많은 요청된 기능의 구현을 차단할 것입니다. 이러한 기능의 대부분은 GitLab 컨테이너 레지스트리를 사용하는 인스턴스에만 사용 가능할 것입니다. 이들은 Docker Distribution 또는 OCI 명세의 일부가 아니며, 우리는 타사 레지스트리와 호환되는 대체 옵션을 제공할 수 없을 것입니다.
따라서 GitLab 컨테이너 레지스트리를 사용하는 기능은 타사 레지스트리를 사용하는 경우 비활성화될 것입니다.
GitLab Rails와의 변경 사항 동기화
현재, GitLab Rails와 GitLab 컨테이너 레지스트리 릴리스 및 배포는 완전히 독립적으로 이루어져왔습니다. 우리는 설명된 태그 삭제 기능 이외에 새로운 API 기능이나 파괴적인 변경 사항을 도입하지 않았기 때문입니다.
레지스트리는 GitLab Rails 변경 사항과는 독립적으로 유지될 것이지만, 중장기적으로 새로운 기능이나 파괴적인 변경 사항의 구현은 GitLab Rails의 특정 최소 버전에 해당 변경 사항이 의존하게 될 것입니다.
예를 들어, 각 리포지터리의 크기를 추적하기 위해서는 메타데이터 데이터베이스를 확장하여 정보를 저장한 다음에 이를 GitLab Rails로 확장하는 HTTP API를 통해 전파할 수 있습니다. GitLab Rails에서 이러한 새로운 정보는 아마도 해당 데이터베이스에 저장되고 UI/API 수준에서 새로운 기능을 제공하기 위해 처리될 것입니다.
이러한 변경 사항은 GitLab Rails와 GitLab 컨테이너 레지스트리의 릴리스 및 배포간의 동기화가 필요하게 될 것입니다. 왜냐하면 전자는 후자의 특정 버전에 의존하게 될 것이기 때문입니다.
기능 토글링
레지스트리의 특정 버전에 의존하는 모든 GitLab Rails 기능은 레지스트리 공급업체와 버전을 검증하여 보호되어야 합니다.
이는 이미 태그 삭제 기능을 사용하여 태그를 삭제해야 하는지 여부(내용은 GitLab 컨테이너 레지스트리 v2.8.1+에서만 사용 가능)를 확인하기 위해 수행됩니다. 이 경우에 GitLab Rails는 OPTIONS
요청을 레지스트리 태그 경로로 보내어 DELETE
메서드가 지원되는지 여부를 결정합니다.
또는 장기적인 범용 솔루션으로, 레지스트리 공급업체, 버전 및 지원되는 기능(후자 두 가지는 GitLab인 경우에만 적용)을 확인하고 GitLab Rails 데이터베이스에 지속적으로 저장해야 합니다. 이 정보는 실시간으로 사용되어 기능을 토글하거나 가능한 경우 대체 방법으로 되돌아가는 데 사용될 수 있습니다. 이 접근 방법의 초기 구현은 #204839의 일환으로 소개되었습니다. 현재 이는 메트릭 목적으로만 사용됩니다. 레지스트리가 핫스왑될 수 있는 Self-managed 인스턴스에서 버전 정보를 최신 상태로 유지할 수 있도록 보장하기 위해 추가 개선이 필요합니다.
릴리스 및 배포
위에서 설명한 바와 같이, 기능 토글링은 레지스트리 버전이 새로운 기능을 지원하는 버전이 아직 사용 가능하지 않을 때 GitLab Rails가 기능을 제공하기 위해 동작 가능하도록, 동기화되지 않은 릴리스와 배포에 대한 최후의 방어선을 제공하게 됩니다.
하지만, GitLab Rails 및 GitLab 컨테이너 레지스트리의 릴리스 및 배포는 지연을 피하기 위해 동기화되어야 합니다. GitLab Rails와는 달리, 레지스트리 릴리스 및 배포는 매뉴얼 프로세스이므로 GitLab Rails 변경이 해당 레지스트리 변경 후에만 릴리스 및 배포되도록 유지 관리자에 의해 특별한 주의를 기울여야 합니다.
이 프로세스를 강화하기 위한 솔루션으로, GitLab Rails 코드베이스에 최소 필요한 레지스트리 버전을 포함한 파일을 추가할 수 있습니다. 이 파일은 특정 레지스트리 버전에 의존하는 모든 변경에 대해 업데이트되어야 합니다. 또한 GitLab Rails을 릴리스하고 배포할 때 고려되어, 지정된 최소 필요 레지스트리 버전이 배포된 후에만 파이프라인이 진행되도록 보장해야 합니다.
반복 작업
- 메타데이터 데이터베이스 스키마 설계;
- 데이터베이스를 사용하여 메타데이터 관리 지원 추가;
- 소형, 중형 및 대형 리포지터리의 이주를 용이하게 하는 계획 및 도구 설계;
- 온라인 가비지 수집 구현;
- GitLab.com을 위한 스테이징 및 프로덕션 데이터베이스 클러스터 생성;
- GitLab.com을 위한 자동 배포 파이프라인 생성;
- 기존 레지스트리의 배포 및 점진적 이주;
- Self-managed 설치를 위한 메타데이터 데이터베이스 지원 롤아웃.
에픽에서 모든 작업의보다 자세한 디렉터리 및 주기적인 진행 업데이트를 확인할 수 있습니다: &2313.