InfoGrab DocsInfoGrab Docs

새 패키지 형식 개발

요약

이 문서는 새 패키지 관리 시스템에 대한 지원을 GitLab에 추가하는 과정을 안내합니다. 이미 지원되는 형식은 패키지 및 레지스트리 문서를 참고합니다. 백엔드 변경만으로 새 형식을 추가할 수 있습니다. 기존 데이터베이스 모델은 다음을 전제로 합니다.

이 문서는 새 패키지 관리 시스템에 대한 지원을 GitLab에 추가하는 과정을 안내합니다.

이미 지원되는 형식은 패키지 및 레지스트리 문서를 참고합니다.

백엔드 변경만으로 새 형식을 추가할 수 있습니다. 이 가이드는 개괄적인 내용이며 코드를 어떻게 작성해야 하는지는 다루지 않습니다. 다만 다음 머지 리퀘스트에서 좋은 예를 확인할 수 있습니다.

일반 정보#

기존 데이터베이스 모델은 다음을 전제로 합니다.

  • 모든 패키지는 프로젝트에 속합니다.
  • 모든 패키지 파일은 패키지에 속합니다.
  • 하나의 패키지는 하나 이상의 패키지 파일을 가질 수 있습니다.
  • 패키지 모델은 패키지와 그 버전에 대한 정보를 저장하는 것을 기반으로 합니다.

API 엔드포인트#

패키지 시스템은 API를 통해 GitLab과 연동됩니다. 예를 들어 lib/api/npm_project_packages.rb는 npm 클라이언트와 연동하기 위한 API 엔드포인트를 구현합니다. 따라서 가장 먼저 할 일은 패키지 시스템 클라이언트가 동작하는 데 필요한 API 엔드포인트를 담은 lib/api/your_name_project_packages.rb 파일을 새로 추가하는 것입니다. 보통 다음과 같은 엔드포인트가 필요합니다.

  • 패키지 정보 GET.
  • 패키지 파일 콘텐츠 GET.
  • 패키지 업로드 PUT.

패키지는 프로젝트에 속하므로, 업로드와 다운로드를 위한 프로젝트 수준 엔드포인트(리모트)가 필요합니다. 예를 들면 다음과 같습니다.

GET https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/
PUT https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/

그룹 수준과 인스턴스 수준 엔드포인트는 프로젝트 수준 엔드포인트가 프로덕션에서 사용 가능해진 뒤에 고려합니다.

리모트 계층 구조#

패키지는 여러 접근 수준으로 범위가 지정되며, 이는 일반적으로 리모트 설정으로 구성합니다. 리모트 엔드포인트는 프로젝트 수준으로 설정할 수 있으며, 이 경우 패키지를 설치할 때 해당 프로젝트에 속한 패키지만 보입니다. 또는 그룹 수준 엔드포인트를 사용해 해당 그룹의 모든 패키지를 볼 수 있게 할 수 있습니다. 마지막으로 인스턴스 수준 엔드포인트를 사용하면 GitLab 인스턴스 전체의 모든 패키지를 볼 수 있습니다.

MVC 로는 프로젝트 수준 엔드포인트부터 시작하는 것을 권장합니다. 리모트 계층 구조의 일반적인 반복 계획은 다음 순서입니다.

  • 프로젝트에서 게시 및 설치
  • 그룹에서 설치
  • 인스턴스에서 게시 및 설치(GitLab Self-Managed 고객 대상)

인스턴스 수준 엔드포인트를 사용하려면 더 엄격한 명명 규칙이 필요합니다.

Note

Composer 패키지 명명 범위는 인스턴스 수준입니다.

명명 규칙#

인스턴스 수준 엔드포인트에서 이름 충돌을 피하려면 패키지가 속한 프로젝트를 식별할 수 있는 패키지 명명 규칙을 정의해야 합니다. 보통 패키지 이름에 프로젝트 ID 나 전체 프로젝트 경로를 사용합니다. 예시를 포함한 자세한 내용은 인스턴스 리모트용 패키지 레시피 명명 규칙을 참고합니다.

그룹 및 프로젝트 수준 엔드포인트에서는 명명 제약이 덜하며, 두 패키지 이름이 충돌하지 않도록 확인하는 책임은 그룹과 프로젝트 멤버에게 있습니다. 다만 시스템은 사용자가 특정 범위 안에서 기존 이름을 다시 사용하지 못하도록 막아야 합니다.

그 밖에는 해당 패키지 관리자의 명명 규칙을 따르고, 해당 패키지 유형의 package.md 모델에 검증을 포함합니다.

서비스 및 파인더#

패키지나 패키지 파일 레코드를 생성하거나 패키지를 찾는 등의 작업 로직은 API 파일이 아니라 서비스와 파인더에 두어야 합니다. 공통 패키지 로직을 최대한 한데 모으기 위해, 가능하면 기존 서비스와 파인더를 사용하거나 확장합니다.

구성#

GitLab의 설정 파일(gitlab.rb 또는 gitlab.yml)에는 packages 섹션이 있습니다. 이 섹션은 GitLab 이 지원하는 모든 패키지 시스템에 적용됩니다. 보통은 여기에 무언가를 추가할 필요가 없습니다.

패키지는 오브젝트 스토리지를 사용하도록 구성할 수 있으므로 작성하는 코드도 이를 지원해야 합니다.

MVC 접근 방식#

새 패키지 시스템은 MVC 방식으로 GitLab에 통합합니다. 따라서 첫 반복에서는 다음의 최소 사용자 동작을 지원해야 합니다.

  • GitLab job 토큰, 개인 액세스 토큰, 프로젝트 액세스 토큰, 배포 토큰을 통한 인증
  • 패키지 업로드 및 사용자 인터페이스에서의 기본 메타데이터 표시
  • 패키지 풀
  • 필수 동작

필수 동작은 해당 패키지 관리자 CLI가 정상적으로 동작하도록 GitLab 이 처리해야 하는 추가 요청 전부를 말합니다. 검색 기능이거나 패키지에 대한 메타 정보를 제공하는 엔드포인트일 수 있습니다. 예를 들면 다음과 같습니다.

  • NuGet에서는 Visual Studio를 지원하기 위해 첫 MVC 반복에서 검색 요청을 구현했습니다.
  • npm에서는 npm 이 tarball URL을 가져오는 데 사용하는 메타데이터 엔드포인트가 있습니다.

첫 MVC 반복에서는 리모트 계층 구조의 프로젝트 수준에 머무르는 것을 권장합니다. 다른 수준은 이후 머지 리퀘스트에서 다룰 수 있습니다.

MVC는 보통 두 단계로 진행됩니다.

반복을 작게 유지하기#

새 패키지 관리자를 구현할 때는 기본 사용에 필요한 모든 엔드포인트와 서비스를 하나의 큰 머지 리퀘스트에 담고 싶어집니다. 대신 다음과 같이 진행합니다.

  1. API 엔드포인트를 기능 플래그 뒤에 둡니다.
  2. 리뷰 과정을 짧게 하도록 다운로드나 업로드 같은 엔드포인트·동작마다 머지 리퀘스트를 따로 제출합니다.

분석#

이 단계의 목표는 해당 패키지 시스템이 사용하는 API에 대해 가능한 한 많은 정보를 수집하는 것입니다. 포함하면 유용한 항목은 다음과 같습니다.

  • 인증: 어떤 인증 방식을 사용할 수 있는지(OAuth, Basic Authorization 등). GitLab 사용자는 개인 액세스 토큰을 쓰고 싶어 하는 경우가 많다는 점을 염두에 둡니다. MVC 첫 반복에는 필요하지 않지만 CI/CD job 토큰도 언젠가는 지원해야 합니다.
  • 요청: MVC가 동작하는 데 필요한 요청이 무엇인지 파악합니다. 가능하면 MVC에 필요한 모든 요청(필수 동작 포함) 목록을 작성합니다. 더 나아가 각 요청의 요청 본문과 응답 본문을 담은 예시를 제시할 수 있습니다.
  • 업로드: 업로드 과정이 어떻게 동작하는지 면밀히 분석합니다. 이 요청이 구현하기 가장 복잡할 가능성이 높습니다. 업로드는 여러 방식(본문 또는 멀티파트)으로 인코딩될 수 있고 완전히 다른 형식일 수도 있으므로(예: 패키지 파일이 특정 필드의 Base64 값으로 들어 있는 JSON 구조) 여기서는 상세한 분석이 필요합니다. 이러한 인코딩 차이는 GitLab과 GitLab Workhorse의 구현을 조금씩 다르게 만듭니다. 자세한 내용은 파일 업로드를 참고합니다.
  • 엔드포인트: GitLab에 구현할 엔드포인트 URL 목록을 제안합니다.
  • 작업 분할: MVC를 점진적으로 구축하기 위한 변경 목록을 제안합니다. 이를 통해 작업량을 가늠할 수 있습니다. 다음은 사례별로 조정해야 하는 예시 목록입니다.
    1. 빈 파일 구조(API 파일, 해당 패키지의 기본 서비스)
    2. 패키지 관리자에 "로그인"하기 위한 인증 체계
    3. 메타데이터 식별 및 해당 테이블 생성
    4. 오브젝트 스토리지 직접 업로드를 위한 Workhorse 라우트
    5. 업로드/게시에 필요한 엔드포인트
    6. 설치/다운로드에 필요한 엔드포인트
    7. 필수 동작에 필요한 엔드포인트

분석에는 보통 한 마일스톤 전체가 걸리지만, 같은 마일스톤에 구현을 시작하는 것도 불가능하지는 않습니다.

특히 업로드 요청은 GitLab Workhorse 프로젝트의 요구 사항을 수반할 수 있습니다. 이 프로젝트는 Rails 백엔드와 릴리스 주기가 다릅니다. 업로드 요청 분석이 끝나는 즉시 해당 프로젝트에 이슈를 여는 것을 강력히 권장합니다. 그래야 Rails 백엔드에 업로드 요청을 구현할 때 GitLab Workhorse가 이미 준비돼 있습니다.

구현#

여러 머지 리퀘스트의 구현 방식은 패키지 시스템 통합마다 다릅니다. 기여자는 구현 단계의 몇 가지 중요한 측면을 고려해야 합니다.

인증#

MVC는 처음부터 개인 액세스 토큰을 지원해야 합니다. 이 토큰에 대해 OAuth와 Basic Access 두 가지 방식을 지원합니다.

OAuth 인증은 이미 지원됩니다. 예시는 npm API에서 확인할 수 있습니다.

Basic Access 인증 지원은 Conan API의 예시처럼 API 헬퍼의 특정 함수를 재정의해 구현합니다. 이 인증 방식에서는 일부 클라이언트가 먼저 인증되지 않은 요청을 보내고 WWW-Authenticate 필드가 담긴 401 Unauthorized 응답을 기다린 뒤 인증 정보를 담은 요청을 다시 보낸다는 점을 염두에 둡니다. 이 경우 GitLab 이 401 Unauthorized 응답을 처리해야 하므로 구현이 더 복잡합니다. NuGet API가 이 경우를 지원합니다.

인가#

프로젝트 권한과 그룹 권한에는 read_package, create_package, destroy_package가 있습니다. 각 엔드포인트는 처리를 계속하기 전에 프로젝트나 그룹에 대해 요청 사용자를 인가해야 합니다.

데이터베이스 및 메타데이터 처리#

현재 데이터베이스 모델을 사용해 각 패키지의 이름과 버전을 저장할 수 있습니다. 새 패키지를 업로드할 때마다 Package 레코드를 새로 만들거나 기존 레코드에 파일을 추가할 수 있습니다. PackageFile은 파일 name, side, sha1 등 파일 관련 정보를 모두 저장할 수 있어야 합니다.

특정 패키지 시스템 지원에만 필요한 데이터가 있다면 별도의 메타데이터 모델을 만드는 방안을 고려합니다. 패키지별 데이터의 예로는 packages_maven_metadata 테이블과 Packages::Maven::Metadatum 모델을, 패키지 파일별 데이터의 예로는 packages_conan_file_metadata 테이블과 Packages::Conan::FileMetadatum 모델을 참고합니다.

특정 패키지 관리자에만 해당하는 동작이 있다면 해당 메서드를 메타데이터 모델에 추가하고 패키지 모델에서 위임합니다.

기존 패키지 UI는 packages_packages와 packages_package_files 테이블의 정보만 표시합니다. 메타데이터 테이블에 저장된 데이터를 표시해야 한다면 ~frontend 변경이 필요합니다.

파일 업로드#

파일 업로드는 오브젝트 가속 업로드를 사용해 GitLab Workhorse가 처리해야 합니다. 이는 GitLab으로 들어오는 모든 요청을 검사하는 workhorse 프록시가 업로드 요청을 가로채 파일을 업로드한 다음, 파일 자체가 아니라 메타데이터와 파일 위치만 담은 요청을 GitLab 본체 코드베이스로 전달한다는 뜻입니다. 이 과정의 개요는 개발 문서에서 확인할 수 있습니다.

코드 관점에서 이는 추가하는 업로드 엔드포인트(인스턴스, 그룹, 프로젝트)마다 GitLab Workhorse 프로젝트에 라우트를 추가해야 한다는 뜻입니다. 이 머지 리퀘스트는 Conan의 인스턴스 수준 엔드포인트를 workhorse에 추가하는 예를 보여 줍니다. 같은 파일에서 Maven의 프로젝트 수준 엔드포인트 구현도 확인할 수 있습니다.

라우트를 추가한 뒤에는 API 파일에 업로드 엔드포인트의 /authorize 버전을 추가해야 합니다. 이 예시는 Maven에 추가된 엔드포인트를 보여 줍니다. /authorize 엔드포인트는 workhorse의 요청을 검증하고 인가하며, 그 아래에 일반 업로드 엔드포인트를 구현해 Workhorse가 제공하는 메타데이터로 패키지 레코드를 생성합니다. Workhorse는 유형, 크기, 여러 체크섬 형식 등 다양한 파일 메타데이터를 제공합니다.

테스트 목적으로는 로컬 개발 환경에서 오브젝트 스토리지를 활성화하는 것이 유용할 수 있습니다.

파일 크기 제한#

GitLab 패키지 레지스트리에 업로드되는 파일은 형식별로 제한됩니다. GitLab.com에서는 타임아웃 문제와 남용을 막기 위해 보통 5GB로 설정돼 있습니다.

Packages::Package 모델에 새 패키지 유형을 추가할 때는 이 예시처럼 크기 제한을 추가하거나, 파일 크기 제한이 적용되지 않는다면 관련 테스트를 갱신해야 합니다. 크기 제한이 적용되지 않는 유일한 경우는 해당 패키지 형식이 패키지 파일을 업로드하고 저장하지 않을 때입니다.

GitLab.com의 속도 제한#

패키지 관리자 클라이언트는 GitLab.com 표준 API 속도 제한을 초과할 정도로 빠르게 요청을 보낼 수 있습니다. 이 경우 429 Too Many Requests 오류가 발생합니다.

GitLab은 더 높은 속도 제한을 허용하는 경로를 열어 두었습니다. 불가능한 경우가 아니라면 새 패키지 관리자는 확장된 패키지 속도 제한을 활용할 수 있도록 이 규칙을 따라야 합니다.

다음 라우트 접두사는 더 높은 속도 제한을 보장합니다.

/api/v4/packages/
/api/v4/projects/:project_id/packages/
/api/v4/groups/:group_id/-/packages/

MVC 체크리스트#

새 패키지 관리자에 대한 지원을 GitLab에 추가할 때 첫 반복에는 다음 기능이 포함돼야 합니다. 필요하면 여러 머지 리퀘스트로 나누어 추가해도 되지만, 기능 플래그를 제거하는 시점에는 모든 기능이 구현돼 있어야 합니다.

  • 프로젝트 수준 API
  • 푸시 이벤트 추적
  • 풀 이벤트 추적
  • 개인 액세스 토큰을 통한 인증
  • Job Token을 통한 인증
  • Deploy Token을 통한 인증(그룹 및 프로젝트)
  • 파일 크기 제한
  • 파일 형식 가드(해당 패키지 유형의 유효한 파일 형식만 허용)
  • 검증이 포함된 이름 정규식
  • 검증이 포함된 버전 정규식
  • 가속 업로드를 위한 Workhorse 라우트
  • 패키지 메타데이터 추출용 백그라운드 워커(해당하는 경우)
  • 문서(기능 사용 방법)
  • API 문서(curl 예시를 포함한 개별 엔드포인트)
  • db/fixtures/development/26_packages.rb에 시드 데이터 추가
  • Grafana 차트용 런북 갱신
  • 최소한 패키지 게시와 설치에 대한 종단 간 기능 테스트

향후 작업#

MVC를 진행하다 보면 MVC에 필수는 아니지만 더 나은 사용자 경험을 제공할 수 있는 기능을 발견할 수 있습니다. 이러한 기능을 눈여겨보고 이슈를 여는 것이 대체로 좋습니다.

몇 가지 예는 다음과 같습니다.

  1. 검색에 필요한 엔드포인트
  2. 추가 패키지 정보와 메타데이터를 표시하기 위한 프론트엔드 업데이트
  3. 파일 크기 제한
  4. 메트릭 추적
  5. 패키지에서 더 많은 메타데이터 필드를 읽어 프론트엔드에서 사용할 수 있게 하기. 예를 들어 패키지에 태그를 다는 기능은 흔합니다. 이러한 태그는 백엔드에서 읽고 저장한 다음 패키지 UI에 표시할 수 있습니다.
  6. 리모트 계층 구조 상위 수준을 위한 엔드포인트. 이 단계에서는 명명 규칙을 만들어야 할 수 있습니다.

예외#

이 문서는 GitLab에 이미 존재하는 구조와 로직에 맞춰 패키지 관리자를 구현하는 방법에 대한 지침일 뿐입니다. 이 구조는 어떤 패키지 관리자든 수용할 수 있을 만큼 확장 가능하고 유연하게 설계됐지만, 특정 패키지 관리자의 제약이나 요구 때문에 벗어날 타당한 이유가 있다면 가장 효율적인 결과를 내기 위해 구현 이슈나 머지 리퀘스트에서 이를 제기하고 논의해야 합니다.

새 패키지 형식 개발

GitLab v19.4
원문 보기

요약

이 문서는 새 패키지 관리 시스템에 대한 지원을 GitLab에 추가하는 과정을 안내합니다. 이미 지원되는 형식은 패키지 및 레지스트리 문서를 참고합니다. 백엔드 변경만으로 새 형식을 추가할 수 있습니다. 기존 데이터베이스 모델은 다음을 전제로 합니다.

이 문서는 새 패키지 관리 시스템에 대한 지원을 GitLab에 추가하는 과정을 안내합니다.

이미 지원되는 형식은 패키지 및 레지스트리 문서를 참고합니다.

백엔드 변경만으로 새 형식을 추가할 수 있습니다. 이 가이드는 개괄적인 내용이며 코드를 어떻게 작성해야 하는지는 다루지 않습니다. 다만 다음 머지 리퀘스트에서 좋은 예를 확인할 수 있습니다.

일반 정보#

기존 데이터베이스 모델은 다음을 전제로 합니다.

  • 모든 패키지는 프로젝트에 속합니다.
  • 모든 패키지 파일은 패키지에 속합니다.
  • 하나의 패키지는 하나 이상의 패키지 파일을 가질 수 있습니다.
  • 패키지 모델은 패키지와 그 버전에 대한 정보를 저장하는 것을 기반으로 합니다.

API 엔드포인트#

패키지 시스템은 API를 통해 GitLab과 연동됩니다. 예를 들어 lib/api/npm_project_packages.rb는 npm 클라이언트와 연동하기 위한 API 엔드포인트를 구현합니다. 따라서 가장 먼저 할 일은 패키지 시스템 클라이언트가 동작하는 데 필요한 API 엔드포인트를 담은 lib/api/your_name_project_packages.rb 파일을 새로 추가하는 것입니다. 보통 다음과 같은 엔드포인트가 필요합니다.

  • 패키지 정보 GET.
  • 패키지 파일 콘텐츠 GET.
  • 패키지 업로드 PUT.

패키지는 프로젝트에 속하므로, 업로드와 다운로드를 위한 프로젝트 수준 엔드포인트(리모트)가 필요합니다. 예를 들면 다음과 같습니다.

GET https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/
PUT https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/

그룹 수준과 인스턴스 수준 엔드포인트는 프로젝트 수준 엔드포인트가 프로덕션에서 사용 가능해진 뒤에 고려합니다.

리모트 계층 구조#

패키지는 여러 접근 수준으로 범위가 지정되며, 이는 일반적으로 리모트 설정으로 구성합니다. 리모트 엔드포인트는 프로젝트 수준으로 설정할 수 있으며, 이 경우 패키지를 설치할 때 해당 프로젝트에 속한 패키지만 보입니다. 또는 그룹 수준 엔드포인트를 사용해 해당 그룹의 모든 패키지를 볼 수 있게 할 수 있습니다. 마지막으로 인스턴스 수준 엔드포인트를 사용하면 GitLab 인스턴스 전체의 모든 패키지를 볼 수 있습니다.

MVC 로는 프로젝트 수준 엔드포인트부터 시작하는 것을 권장합니다. 리모트 계층 구조의 일반적인 반복 계획은 다음 순서입니다.

  • 프로젝트에서 게시 및 설치
  • 그룹에서 설치
  • 인스턴스에서 게시 및 설치(GitLab Self-Managed 고객 대상)

인스턴스 수준 엔드포인트를 사용하려면 더 엄격한 명명 규칙이 필요합니다.

Note

Composer 패키지 명명 범위는 인스턴스 수준입니다.

명명 규칙#

인스턴스 수준 엔드포인트에서 이름 충돌을 피하려면 패키지가 속한 프로젝트를 식별할 수 있는 패키지 명명 규칙을 정의해야 합니다. 보통 패키지 이름에 프로젝트 ID 나 전체 프로젝트 경로를 사용합니다. 예시를 포함한 자세한 내용은 인스턴스 리모트용 패키지 레시피 명명 규칙을 참고합니다.

그룹 및 프로젝트 수준 엔드포인트에서는 명명 제약이 덜하며, 두 패키지 이름이 충돌하지 않도록 확인하는 책임은 그룹과 프로젝트 멤버에게 있습니다. 다만 시스템은 사용자가 특정 범위 안에서 기존 이름을 다시 사용하지 못하도록 막아야 합니다.

그 밖에는 해당 패키지 관리자의 명명 규칙을 따르고, 해당 패키지 유형의 package.md 모델에 검증을 포함합니다.

서비스 및 파인더#

패키지나 패키지 파일 레코드를 생성하거나 패키지를 찾는 등의 작업 로직은 API 파일이 아니라 서비스와 파인더에 두어야 합니다. 공통 패키지 로직을 최대한 한데 모으기 위해, 가능하면 기존 서비스와 파인더를 사용하거나 확장합니다.

구성#

GitLab의 설정 파일(gitlab.rb 또는 gitlab.yml)에는 packages 섹션이 있습니다. 이 섹션은 GitLab 이 지원하는 모든 패키지 시스템에 적용됩니다. 보통은 여기에 무언가를 추가할 필요가 없습니다.

패키지는 오브젝트 스토리지를 사용하도록 구성할 수 있으므로 작성하는 코드도 이를 지원해야 합니다.

MVC 접근 방식#

새 패키지 시스템은 MVC 방식으로 GitLab에 통합합니다. 따라서 첫 반복에서는 다음의 최소 사용자 동작을 지원해야 합니다.

  • GitLab job 토큰, 개인 액세스 토큰, 프로젝트 액세스 토큰, 배포 토큰을 통한 인증
  • 패키지 업로드 및 사용자 인터페이스에서의 기본 메타데이터 표시
  • 패키지 풀
  • 필수 동작

필수 동작은 해당 패키지 관리자 CLI가 정상적으로 동작하도록 GitLab 이 처리해야 하는 추가 요청 전부를 말합니다. 검색 기능이거나 패키지에 대한 메타 정보를 제공하는 엔드포인트일 수 있습니다. 예를 들면 다음과 같습니다.

  • NuGet에서는 Visual Studio를 지원하기 위해 첫 MVC 반복에서 검색 요청을 구현했습니다.
  • npm에서는 npm 이 tarball URL을 가져오는 데 사용하는 메타데이터 엔드포인트가 있습니다.

첫 MVC 반복에서는 리모트 계층 구조의 프로젝트 수준에 머무르는 것을 권장합니다. 다른 수준은 이후 머지 리퀘스트에서 다룰 수 있습니다.

MVC는 보통 두 단계로 진행됩니다.

반복을 작게 유지하기#

새 패키지 관리자를 구현할 때는 기본 사용에 필요한 모든 엔드포인트와 서비스를 하나의 큰 머지 리퀘스트에 담고 싶어집니다. 대신 다음과 같이 진행합니다.

  1. API 엔드포인트를 기능 플래그 뒤에 둡니다.
  2. 리뷰 과정을 짧게 하도록 다운로드나 업로드 같은 엔드포인트·동작마다 머지 리퀘스트를 따로 제출합니다.

분석#

이 단계의 목표는 해당 패키지 시스템이 사용하는 API에 대해 가능한 한 많은 정보를 수집하는 것입니다. 포함하면 유용한 항목은 다음과 같습니다.

  • 인증: 어떤 인증 방식을 사용할 수 있는지(OAuth, Basic Authorization 등). GitLab 사용자는 개인 액세스 토큰을 쓰고 싶어 하는 경우가 많다는 점을 염두에 둡니다. MVC 첫 반복에는 필요하지 않지만 CI/CD job 토큰도 언젠가는 지원해야 합니다.
  • 요청: MVC가 동작하는 데 필요한 요청이 무엇인지 파악합니다. 가능하면 MVC에 필요한 모든 요청(필수 동작 포함) 목록을 작성합니다. 더 나아가 각 요청의 요청 본문과 응답 본문을 담은 예시를 제시할 수 있습니다.
  • 업로드: 업로드 과정이 어떻게 동작하는지 면밀히 분석합니다. 이 요청이 구현하기 가장 복잡할 가능성이 높습니다. 업로드는 여러 방식(본문 또는 멀티파트)으로 인코딩될 수 있고 완전히 다른 형식일 수도 있으므로(예: 패키지 파일이 특정 필드의 Base64 값으로 들어 있는 JSON 구조) 여기서는 상세한 분석이 필요합니다. 이러한 인코딩 차이는 GitLab과 GitLab Workhorse의 구현을 조금씩 다르게 만듭니다. 자세한 내용은 파일 업로드를 참고합니다.
  • 엔드포인트: GitLab에 구현할 엔드포인트 URL 목록을 제안합니다.
  • 작업 분할: MVC를 점진적으로 구축하기 위한 변경 목록을 제안합니다. 이를 통해 작업량을 가늠할 수 있습니다. 다음은 사례별로 조정해야 하는 예시 목록입니다.
    1. 빈 파일 구조(API 파일, 해당 패키지의 기본 서비스)
    2. 패키지 관리자에 "로그인"하기 위한 인증 체계
    3. 메타데이터 식별 및 해당 테이블 생성
    4. 오브젝트 스토리지 직접 업로드를 위한 Workhorse 라우트
    5. 업로드/게시에 필요한 엔드포인트
    6. 설치/다운로드에 필요한 엔드포인트
    7. 필수 동작에 필요한 엔드포인트

분석에는 보통 한 마일스톤 전체가 걸리지만, 같은 마일스톤에 구현을 시작하는 것도 불가능하지는 않습니다.

특히 업로드 요청은 GitLab Workhorse 프로젝트의 요구 사항을 수반할 수 있습니다. 이 프로젝트는 Rails 백엔드와 릴리스 주기가 다릅니다. 업로드 요청 분석이 끝나는 즉시 해당 프로젝트에 이슈를 여는 것을 강력히 권장합니다. 그래야 Rails 백엔드에 업로드 요청을 구현할 때 GitLab Workhorse가 이미 준비돼 있습니다.

구현#

여러 머지 리퀘스트의 구현 방식은 패키지 시스템 통합마다 다릅니다. 기여자는 구현 단계의 몇 가지 중요한 측면을 고려해야 합니다.

인증#

MVC는 처음부터 개인 액세스 토큰을 지원해야 합니다. 이 토큰에 대해 OAuth와 Basic Access 두 가지 방식을 지원합니다.

OAuth 인증은 이미 지원됩니다. 예시는 npm API에서 확인할 수 있습니다.

Basic Access 인증 지원은 Conan API의 예시처럼 API 헬퍼의 특정 함수를 재정의해 구현합니다. 이 인증 방식에서는 일부 클라이언트가 먼저 인증되지 않은 요청을 보내고 WWW-Authenticate 필드가 담긴 401 Unauthorized 응답을 기다린 뒤 인증 정보를 담은 요청을 다시 보낸다는 점을 염두에 둡니다. 이 경우 GitLab 이 401 Unauthorized 응답을 처리해야 하므로 구현이 더 복잡합니다. NuGet API가 이 경우를 지원합니다.

인가#

프로젝트 권한과 그룹 권한에는 read_package, create_package, destroy_package가 있습니다. 각 엔드포인트는 처리를 계속하기 전에 프로젝트나 그룹에 대해 요청 사용자를 인가해야 합니다.

데이터베이스 및 메타데이터 처리#

현재 데이터베이스 모델을 사용해 각 패키지의 이름과 버전을 저장할 수 있습니다. 새 패키지를 업로드할 때마다 Package 레코드를 새로 만들거나 기존 레코드에 파일을 추가할 수 있습니다. PackageFile은 파일 name, side, sha1 등 파일 관련 정보를 모두 저장할 수 있어야 합니다.

특정 패키지 시스템 지원에만 필요한 데이터가 있다면 별도의 메타데이터 모델을 만드는 방안을 고려합니다. 패키지별 데이터의 예로는 packages_maven_metadata 테이블과 Packages::Maven::Metadatum 모델을, 패키지 파일별 데이터의 예로는 packages_conan_file_metadata 테이블과 Packages::Conan::FileMetadatum 모델을 참고합니다.

특정 패키지 관리자에만 해당하는 동작이 있다면 해당 메서드를 메타데이터 모델에 추가하고 패키지 모델에서 위임합니다.

기존 패키지 UI는 packages_packages와 packages_package_files 테이블의 정보만 표시합니다. 메타데이터 테이블에 저장된 데이터를 표시해야 한다면 ~frontend 변경이 필요합니다.

파일 업로드#

파일 업로드는 오브젝트 가속 업로드를 사용해 GitLab Workhorse가 처리해야 합니다. 이는 GitLab으로 들어오는 모든 요청을 검사하는 workhorse 프록시가 업로드 요청을 가로채 파일을 업로드한 다음, 파일 자체가 아니라 메타데이터와 파일 위치만 담은 요청을 GitLab 본체 코드베이스로 전달한다는 뜻입니다. 이 과정의 개요는 개발 문서에서 확인할 수 있습니다.

코드 관점에서 이는 추가하는 업로드 엔드포인트(인스턴스, 그룹, 프로젝트)마다 GitLab Workhorse 프로젝트에 라우트를 추가해야 한다는 뜻입니다. 이 머지 리퀘스트는 Conan의 인스턴스 수준 엔드포인트를 workhorse에 추가하는 예를 보여 줍니다. 같은 파일에서 Maven의 프로젝트 수준 엔드포인트 구현도 확인할 수 있습니다.

라우트를 추가한 뒤에는 API 파일에 업로드 엔드포인트의 /authorize 버전을 추가해야 합니다. 이 예시는 Maven에 추가된 엔드포인트를 보여 줍니다. /authorize 엔드포인트는 workhorse의 요청을 검증하고 인가하며, 그 아래에 일반 업로드 엔드포인트를 구현해 Workhorse가 제공하는 메타데이터로 패키지 레코드를 생성합니다. Workhorse는 유형, 크기, 여러 체크섬 형식 등 다양한 파일 메타데이터를 제공합니다.

테스트 목적으로는 로컬 개발 환경에서 오브젝트 스토리지를 활성화하는 것이 유용할 수 있습니다.

파일 크기 제한#

GitLab 패키지 레지스트리에 업로드되는 파일은 형식별로 제한됩니다. GitLab.com에서는 타임아웃 문제와 남용을 막기 위해 보통 5GB로 설정돼 있습니다.

Packages::Package 모델에 새 패키지 유형을 추가할 때는 이 예시처럼 크기 제한을 추가하거나, 파일 크기 제한이 적용되지 않는다면 관련 테스트를 갱신해야 합니다. 크기 제한이 적용되지 않는 유일한 경우는 해당 패키지 형식이 패키지 파일을 업로드하고 저장하지 않을 때입니다.

GitLab.com의 속도 제한#

패키지 관리자 클라이언트는 GitLab.com 표준 API 속도 제한을 초과할 정도로 빠르게 요청을 보낼 수 있습니다. 이 경우 429 Too Many Requests 오류가 발생합니다.

GitLab은 더 높은 속도 제한을 허용하는 경로를 열어 두었습니다. 불가능한 경우가 아니라면 새 패키지 관리자는 확장된 패키지 속도 제한을 활용할 수 있도록 이 규칙을 따라야 합니다.

다음 라우트 접두사는 더 높은 속도 제한을 보장합니다.

/api/v4/packages/
/api/v4/projects/:project_id/packages/
/api/v4/groups/:group_id/-/packages/

MVC 체크리스트#

새 패키지 관리자에 대한 지원을 GitLab에 추가할 때 첫 반복에는 다음 기능이 포함돼야 합니다. 필요하면 여러 머지 리퀘스트로 나누어 추가해도 되지만, 기능 플래그를 제거하는 시점에는 모든 기능이 구현돼 있어야 합니다.

  • 프로젝트 수준 API
  • 푸시 이벤트 추적
  • 풀 이벤트 추적
  • 개인 액세스 토큰을 통한 인증
  • Job Token을 통한 인증
  • Deploy Token을 통한 인증(그룹 및 프로젝트)
  • 파일 크기 제한
  • 파일 형식 가드(해당 패키지 유형의 유효한 파일 형식만 허용)
  • 검증이 포함된 이름 정규식
  • 검증이 포함된 버전 정규식
  • 가속 업로드를 위한 Workhorse 라우트
  • 패키지 메타데이터 추출용 백그라운드 워커(해당하는 경우)
  • 문서(기능 사용 방법)
  • API 문서(curl 예시를 포함한 개별 엔드포인트)
  • db/fixtures/development/26_packages.rb에 시드 데이터 추가
  • Grafana 차트용 런북 갱신
  • 최소한 패키지 게시와 설치에 대한 종단 간 기능 테스트

향후 작업#

MVC를 진행하다 보면 MVC에 필수는 아니지만 더 나은 사용자 경험을 제공할 수 있는 기능을 발견할 수 있습니다. 이러한 기능을 눈여겨보고 이슈를 여는 것이 대체로 좋습니다.

몇 가지 예는 다음과 같습니다.

  1. 검색에 필요한 엔드포인트
  2. 추가 패키지 정보와 메타데이터를 표시하기 위한 프론트엔드 업데이트
  3. 파일 크기 제한
  4. 메트릭 추적
  5. 패키지에서 더 많은 메타데이터 필드를 읽어 프론트엔드에서 사용할 수 있게 하기. 예를 들어 패키지에 태그를 다는 기능은 흔합니다. 이러한 태그는 백엔드에서 읽고 저장한 다음 패키지 UI에 표시할 수 있습니다.
  6. 리모트 계층 구조 상위 수준을 위한 엔드포인트. 이 단계에서는 명명 규칙을 만들어야 할 수 있습니다.

예외#

이 문서는 GitLab에 이미 존재하는 구조와 로직에 맞춰 패키지 관리자를 구현하는 방법에 대한 지침일 뿐입니다. 이 구조는 어떤 패키지 관리자든 수용할 수 있을 만큼 확장 가능하고 유연하게 설계됐지만, 특정 패키지 관리자의 제약이나 요구 때문에 벗어날 타당한 이유가 있다면 가장 효율적인 결과를 내기 위해 구현 이슈나 머지 리퀘스트에서 이를 제기하고 논의해야 합니다.