업로드 개발 가이드라인
GitLab v19.1업로드는 많은 GitLab 기능의 핵심 구성 요소입니다. GitLab 업로드는 기능별로 구성됩니다. 이 페이지는 파일 처리 방식을 결정하는 데 중요한 업로드 설정을 요약합니다. 개별 업로드 전략을 더 자세히 살펴보기 전에, 각 업로드 설정이 어떤 전략에 매핑되는지에 대한 상위 수준의 분류를 먼저 살펴보겠습니다.
업로드는 많은 GitLab 기능의 핵심 구성 요소입니다. GitLab이 업로드를 처리하는 방식을 이해하기 위해, 이 페이지에서는 파일을 스토리지 대상으로 전송하는 주요 메커니즘에 대한 개요를 제공합니다.
GitLab 업로드는 기능별로 구성됩니다. 업로드와 관련된 모든 기능은 동일한 구성 옵션을 제공하지만, 각각 독립적으로 구성할 수 있습니다. 예를 들어, Git LFS 업로드는 CI/CD 빌드 아티팩트 업로드와 독립적으로 구성할 수 있지만, 두 기능 모두 동일한 설정 키 세트를 제공합니다. 이러한 설정은 업로드 처리 방식을 결정하며, 성능과 확장성에 큰 영향을 미칠 수 있습니다.
이 페이지는 파일 처리 방식을 결정하는 데 중요한 업로드 설정을 요약합니다. 이어지는 섹션에서는 각 메커니즘에 대해 더 자세히 설명합니다.
업로드 설정이 업로드 흐름을 결정하는 방식#
개별 업로드 전략을 더 자세히 살펴보기 전에, 각 업로드 설정이 어떤 전략에 매핑되는지에 대한 상위 수준의 분류를 먼저 살펴보겠습니다.
업로드 설정 자체는 업로드 관리에 문서화되어 있습니다. 여기서는 이러한 설정이 GitLab 업로드 로직의 내부를 어떻게 구동하는지에 초점을 맞춥니다. 최상위 수준에서, 업로드된 파일의 대상은 두 가지로 구분됩니다:
이 표에서 x.y.z는 gitlab.yml을 통해 취하는 경로를 지정합니다:
| 설정 | 값 | 동작 |
|---|---|---|
| false | 파일이 |
|
| true | 파일이 |
오브젝트 스토리지를 사용할 때, 관리자는 파일이 해당 버킷으로 이동되는 방법을 제어할 수 있습니다. 이 이동은 다음 방법 중 하나로 수행될 수 있습니다:
개별 Sidekiq 워커도 오브젝트 스토리지에 파일을 저장할 수 있지만, 이 내용은 여기서 다루지 않습니다.
마지막으로, Workhorse는 업로드 버퍼링 메커니즘을 사용하여 Rails 컨트롤러에서 느린 작업을 처리하지 않도록 대부분의 사용자 주도 업로드를 지원합니다. 이 메커니즘은 Workhorse 지원 업로드에서 설명하며, 앞서 설명하는 내용과는 직교적으로 실행됩니다.
이제 각 케이스를 더 자세히 살펴보겠습니다.
로컬 스토리지#
로컬 스토리지는 업로드가 취할 수 있는 가장 간단한 경로입니다. 이것이 GitLab 초기에 업로드를 처리하던 방식입니다. storage_path에서 Rails 애플리케이션이 접근할 수 있는 스토리지 볼륨(디스크 또는 네트워크 연결 스토리지 등)이 있다고 가정합니다. 이 파일 경로는 Rails 루트 디렉터리에 대한 상대 경로이며, 다른 업로드 설정과 마찬가지로 기능별로 구성할 수 있습니다.
클라이언트가 파일 업로드를 전송하면, Workhorse가 먼저 파일을 디스크에 버퍼링합니다. 이 메커니즘은 Workhorse 지원 업로드에서 더 자세히 설명합니다. 요청이 Rails 애플리케이션에 도달하면, 파일이 이미 로컬 스토리지에 존재하므로 Rails는 트랜잭션을 완료하기 위해 지정된 디렉터리로 파일을 이동하기만 하면 됩니다.
로컬 스토리지는 클라우드 네이티브 GitLab(CNG) 설치에서는 사용할 수 없습니다. 따라서 GitLab.com에서도 사용되지 않습니다.
오브젝트 스토리지#
수평적으로 확장 가능한 스토리지를 제공하려면 다음과 같은 오브젝트 스토어 공급자를 사용해야 합니다:
-
Amazon AWS.
-
Google Cloud Storage(GCS).
-
Azure Cloud Storage.
오브젝트 스토리지를 사용하면 두 가지 주요 이점이 있습니다:
-
스토리지 용량 확장 용이성: 클라우드 공급자가 자동으로 처리합니다.
-
GitLab 설치의 수평적 확장 가능: 오브젝트 스토리지에 데이터가 저장되면 여러 GitLab 애플리케이션 서버가 동일한 데이터에 접근할 수 있습니다.
GitLab.com을 포함한 CNG 설치는 항상 오브젝트 스토리지를 사용합니다(GitLab.com의 경우 GCS).
원격 오브젝트 스토어에 업로드할 때의 어려움은 GitLab에서 오브젝트 스토어 공급자로 발송되는 HTTP 요청이 포함된다는 것입니다. 앞에서 언급한 것처럼, 이 HTTP 요청을 전송하는 방법에는 세 가지 전략이 있습니다.
Rails 컨트롤러 업로드#
다이렉트 업로드를 사용할 수 없을 때, Rails는 컨트롤러 create 액션의 일부로 파일을 오브젝트 스토리지에 업로드합니다. 어떤 컨트롤러가 담당하는지는 업로드된 파일의 종류에 따라 다릅니다.
Rails 컨트롤러 업로드는 로컬 스토리지에 업로드하는 것과 매우 유사합니다. 주요 차이점은 Rails가 오브젝트 스토어에 HTTP 요청을 보내야 한다는 것입니다. 이는 CarrierWave Fog 업로더를 통해 수행됩니다.
로컬 스토리지와 마찬가지로, 이 전략은 비용이 많이 드는 I/O 작업 일부를 Ruby와 Rails 외부에서 처리하기 위해 Workhorse 지원의 이점을 받습니다. 다이렉트 업로드는 오브젝트 스토리지에 대한 HTTP PUT 요청도 Puma 외부에서 처리하므로 이 부분에서 더 나은 성능을 발휘합니다.
이 전략은 Puma의 60초 요청 타임아웃이 적용되므로 소용량 파일 업로드에만 적합합니다.
다이렉트 업로드#
다이렉트 업로드는 GitLab.com과 같은 CNG 설치에서 대용량 파일을 오브젝트 스토리지로 이동하는 데 권장되는 방법입니다.
다이렉트 업로드가 활성화되면 Workhorse는:
-
Rails에 요청을 인가(authorize)합니다.
-
파일을 임시 위치로 전송하기 위해 오브젝트 스토어 자체와 연결을 설정합니다.
-
전송이 완료되면 Rails에서 요청을 완료(finalize)합니다.
-
오브젝트 스토리지의 임시 파일을 삭제하여 업로드를 완료합니다.
이 전략은 Workhorse 지원의 다른 형태입니다. Workhorse와 Puma 모두 접근할 수 있는 공유 스토리지에 의존하지 않습니다.
모든 기존 업로드 전략 중에서 다이렉트 업로드는 대용량(기가바이트) 업로드를 가장 잘 처리할 수 있습니다.
디스크 버퍼 업로드#
다이렉트 업로드는 오브젝트 스토리지 설정 내에서 direct_upload가 비활성화된 경우 디스크 버퍼 업로드로 폴백됩니다. /authorize 호출에 대한 응답에는 파일 시스템 경로만 포함됩니다.
sequenceDiagram participant c as Client participant w as Workhorse participant r as Rails participant os as Object Storage
activate c
c ->>+w: POST /some/url/upload
w ->>+r: POST /some/url/upload/authorize
Note over w,r: this request has an empty body
r-->>-w: presigned OS URL
w->>+os: PUT file
Note over w,os: file is stored on a temporary location. Rails select the destination
os-->>-w: request result
w->>+r: POST /some/url/upload
Note over w,r: file was replaced with its location<br>and other metadata
r->>+os: move object to final destination
os-->>-r: request result
opt requires async processing
r->>+redis: schedule a job
redis-->>-r: job is scheduled
end
r-->>-c: request result
deactivate c
w->>-w: cleanup
opt requires async processing
activate sidekiq
sidekiq->>+redis: fetch a job
redis-->>-sidekiq: job
sidekiq->>+os: get object
os-->>-sidekiq: file
sidekiq->>sidekiq: process file
deactivate sidekiq
end
Workhorse 지원 업로드#
파일 콘텐츠를 수신하는 모든 REST 및 GraphQL API는 Workhorse 지원 업로드를 사용해야 합니다.
Workhorse는 다양한 방식으로 지원할 수 있습니다:
-
보통 Workhorse는 업로드를 임시 파일로 버퍼링합니다. Workhorse는 Puma에 임시 파일의 이름과 위치를 알리기 위해 요청에 메타데이터를 추가합니다. 이를 위해 Workhorse와 Puma 간의 공유 임시 스토리지가 필요합니다. 모든 GitLab 설치(CNG 포함)에는 이 공유 임시 스토리지가 있습니다.
-
Workhorse는 때때로 파일을 사전 처리합니다. 예를 들어, CI 아티팩트 업로드의 경우 Workhorse는 ZIP 파일의 콘텐츠에 대한 별도의 인덱스를 생성합니다. Workhorse에서 이 작업을 수행함으로써 Puma 요청 타임아웃을 우회합니다. Sidekiq 백그라운드 처리와 비교했을 때, 이 방법은 GitLab이 파일을 수락했지만 아직 처리하지 않은 중간 상태를 사용자가 보지 않는다는 장점이 있습니다.
-
다이렉트 업로드를 사용하면 Workhorse는 파일을 사전 처리하고 오브젝트 스토리지에 업로드할 수 있습니다. 대용량 파일을 오브젝트 스토리지에 업로드하는 데는 시간이 걸리므로, Workhorse에서 이 작업을 수행함으로써 Puma 요청 타임아웃을 방지합니다.
Workhorse 지원 업로드를 구현하려면 다음이 필요합니다:
-
mimeMultipartUploader또는requestBodyUploader를 사용하여workhorse/internal/upstream/routes.go에 라우트를 추가합니다. -
API 클래스에
/authorize엔드포인트를 생성합니다. 이 엔드포인트는 반드시:
require_gitlab_workhorse! 호출
-
콘텐츠 타입이
Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE인 상태 200을 반환합니다 -
업로더 클래스에서
workhorse_authorize를 호출합니다 -
파일을 수신하는 업로드 엔드포인트를 생성합니다. 이 엔드포인트는 반드시:
require_gitlab_workhorse! 호출
-
파일에 대해 파라미터 타입
::API::Validations::Types::WorkhorseFile을 사용합니다 -
선택적 파일 메타데이터 파라미터(경로, 이름, 타입, 크기, 체크섬)를 선언합니다
-
ObjectStorage::Concern을 포함하는 적절한 업로더 클래스를 사용합니다.
전체 구현 예시는 lib/api/project_import.rb를 참조하세요.
업로드에 대한 추가 정보는 Workhorse 핸들러를 참조하세요.