오브젝트 스토리지
GitLab v19.5Offering: GitLab Self-Managed
요약
GitLab은 다양한 유형의 데이터를 저장하기 위해 오브젝트 스토리지 서비스 사용을 지원합니다. 오브젝트 스토리지를 구성하는 방법에는 두 가지 옵션이 있습니다. 권장. 각 오브젝트 유형별로 고유한 스토리지 연결 구성: 모든 오브젝트가 자체 오브젝트 스토리지 연결 및 구성을 정의합니다.
GitLab은 다양한 유형의 데이터를 저장하기 위해 오브젝트 스토리지 서비스 사용을 지원합니다. NFS보다 권장되며, 오브젝트 스토리지는 일반적으로 성능, 안정성, 확장성이 훨씬 뛰어나기 때문에 대규모 설정에서 더 적합합니다.
오브젝트 스토리지를 구성하는 방법에는 두 가지 옵션이 있습니다.
-
권장. 모든 오브젝트 유형에 대한 단일 스토리지 연결 구성: 단일 자격 증명이 지원되는 모든 오브젝트 유형에 공유됩니다. 이를 통합 형식이라고 합니다.
-
각 오브젝트 유형별로 고유한 스토리지 연결 구성: 모든 오브젝트가 자체 오브젝트 스토리지 연결 및 구성을 정의합니다. 이를 스토리지별 형식이라고 합니다.
이미 스토리지별 형식을 사용하고 있다면, 통합 형식으로 전환하는 방법을 참고합니다.
데이터를 로컬에 저장하고 있다면, 오브젝트 스토리지로 마이그레이션하는 방법을 참고합니다.
오브젝트 스토리지 공급자 지원#
GitLab은 오브젝트 스토리지에 Fog 라이브러리를 사용하며 다음 세 가지 연결 유형을 지원합니다. 다른 Fog 공급자는 지원되지 않습니다.
| 연결 유형 | provider 값 |
사용 대상 |
|---|---|---|
| S3 호환 | AWS |
Amazon S3 및 모든 S3 호환 서비스 |
| Google Cloud Storage | Google |
Google Cloud Storage |
| Azure Blob Storage | AzureRM |
Azure Blob Storage |
오브젝트 스토리지 서비스가 이 연결 유형 중 하나와 호환된다면, 아래의 해당 연결 설정으로 구성합니다. 공급자 선택은 사용자에게 달려 있습니다.
활성 테스트 커버리지가 있는 공급자#
GitLab은 다음 공급자를 활발히 테스트합니다.
- Amazon S3 -
AWS연결 유형. Object Lock은 지원되지 않습니다. 자세한 내용은 이슈 335775를 참고합니다. - Google Cloud Storage -
Google연결 유형. - Azure Blob Storage -
AzureRM연결 유형.
커뮤니티 문서화 공급자#
다음 공급자는 커뮤니티에서 문서화했습니다. GitLab은 이 공급자를 테스트하지 않습니다. 구성 예시는 편의를 위해 제공됩니다. 이 공급자 중 하나를 사용하다가 문제가 발생하면 GitLab 지원팀이 도움을 드리지 못할 수 있습니다.
- Digital Ocean Spaces. S3 호환이며, 공급자별 구성 예시를 참고합니다.
- Oracle Cloud Infrastructure. S3 호환이며, 공급자별 구성 예시를 참고합니다.
- OpenStack Swift (S3 호환 모드).
- Storj Gateway. S3 호환이며, 공급자별 구성 예시를 참고합니다.
- Ceph RGW. S3 호환이며, 공급자별 구성 예시를 참고합니다.
- Hitachi Vantara HCP. S3 호환이며, 공급자별 구성 예시를 참고합니다.
- S3 호환 API를 제공하는 온프레미스 하드웨어 및 어플라이언스.
모든 오브젝트 유형에 대한 단일 스토리지 연결 구성 (통합 형식)#
CI 아티팩트, LFS 파일, 업로드 첨부 파일 등 대부분의 오브젝트 유형은 여러 버킷에 대해 오브젝트 스토리지용 단일 자격 증명을 지정하여 오브젝트 스토리지에 저장할 수 있습니다.
GitLab Helm 차트에서는 통합 형식 구성 방법을 참고합니다.
통합 형식으로 오브젝트 스토리지를 구성하면 다음과 같은 장점이 있습니다.
- 연결 세부 정보가 오브젝트 유형 간에 공유되므로 GitLab 구성을 단순화할 수 있습니다.
- 암호화된 S3 버킷을 사용할 수 있습니다.
- 적절한
Content-MD5헤더와 함께 파일을 S3에 업로드합니다.
통합 형식을 사용하면 직접 업로드가 자동으로 활성화됩니다. 따라서 다음 공급자만 사용할 수 있습니다.
통합 형식 구성은 백업이나 Mattermost에는 사용할 수 없습니다. 백업은 서버 측 암호화를 별도로 구성할 수 있습니다. 지원되는 오브젝트 스토리지 유형의 전체 목록은 표를 참고합니다.
통합 형식을 활성화하면 모든 오브젝트 유형에 대해 오브젝트 스토리지가 활성화됩니다. 일부 버킷을 지정하지 않으면 다음과 같은 오류가 표시될 수 있습니다.
Object storage for <object type> must have a bucket specified
특정 오브젝트 유형에 로컬 스토리지를 사용하려면 특정 기능에 대한 오브젝트 스토리지를 비활성화할 수 있습니다.
공통 매개변수 구성#
통합 형식에서 object_store 섹션은
공통 매개변수 집합을 정의합니다.
| 설정 | 설명 |
|---|---|
enabled |
오브젝트 스토리지를 활성화하거나 비활성화합니다. |
proxy_download |
제공되는 모든 파일의 프록시를 활성화하려면 true로 설정합니다. false로 설정하면 클라이언트가 원격 스토리지에서 직접 다운로드하므로 GitLab 서버의 이그레스 트래픽이 줄어듭니다. |
allowed_download_modes |
지원되는 엔드포인트에서 API 클라이언트가 download_mode 매개변수로 요청할 수 있는 전송 모드입니다. 기본값은 proxy_download로 설정된 모드뿐입니다. 클라이언트가 직접 다운로드를 요청하도록 허용하려면 [proxy, direct]로 설정합니다. |
connection |
아래에 설명된 다양한 연결 옵션입니다. |
storage_options |
서버 측 암호화 등 새 오브젝트를 저장할 때 사용할 옵션입니다. |
objects |
오브젝트별 구성입니다. |
예시는 통합 형식 및 Amazon S3 사용 방법을 참고합니다.
각 오브젝트의 매개변수 구성#
각 오브젝트 유형은 최소한 저장될 버킷 이름을 정의해야 합니다.
다음 표는 사용할 수 있는 유효한 objects를 나열합니다.
| 유형 | 설명 |
|---|---|
artifacts |
CI/CD job 아티팩트 |
external_diffs |
머지 리퀘스트 diff |
uploads |
사용자 업로드 |
lfs |
Git Large File Storage 오브젝트 |
packages |
프로젝트 패키지(예: PyPI, Maven, NuGet) |
dependency_proxy |
Dependency Proxy |
terraform_state |
Terraform 상태 파일 |
pages |
Pages |
ci_secure_files |
보안 파일 |
ci_catalog_bundles |
CI/CD 컴포넌트 번들 |
각 오브젝트 유형 내에서 네 가지 매개변수를 정의할 수 있습니다.
| 설정 | 필수? | 설명 |
|---|---|---|
bucket |
✅ | 오브젝트 유형의 버킷 이름입니다. enabled가 false로 설정된 경우에는 필요하지 않습니다. |
enabled |
❌ | 공통 매개변수를 재정의합니다. |
proxy_download |
❌ | 공통 매개변수를 재정의합니다. |
allowed_download_modes |
❌ | 공통 매개변수를 재정의합니다. |
예시는 통합 형식 및 Amazon S3 사용 방법을 참고합니다.
특정 기능에 대한 오브젝트 스토리지 비활성화#
앞서 설명한 것처럼, enabled 플래그를 false로 설정하여
특정 유형에 대한 오브젝트 스토리지를 비활성화할 수 있습니다.
예를 들어, CI 아티팩트에 대한 오브젝트 스토리지를 비활성화하려면 다음과 같이 설정합니다.
gitlab_rails['object_store']['objects']['artifacts']['enabled'] = false
기능이 완전히 비활성화되면 버킷이 필요하지 않습니다. 예를 들어, 다음 설정으로 CI 아티팩트가 비활성화된 경우 버킷이 필요하지 않습니다.
gitlab_rails['artifacts_enabled'] = false
각 오브젝트 유형별로 고유한 스토리지 연결 구성 (스토리지별 형식)#
스토리지별 형식에서는 모든 오브젝트가 자체 오브젝트 스토리지 연결 및 구성을 정의합니다. 통합 형식이 지원하지 않는 스토리지 유형을 제외하고는 대신 통합 형식을 사용하는 것이 좋습니다. GitLab Helm 차트를 사용할 때는 차트가 오브젝트 스토리지의 통합 형식을 처리하는 방식을 참고합니다.
통합 형식이 아닌 형식에서는 암호화된 S3 버킷 사용이 지원되지 않습니다. 사용하면 ETag 불일치 오류가 발생할 수 있습니다.
스토리지별 형식에서는 직접 업로드가 기본값이 될 수 있습니다. 공유 폴더가 필요하지 않기 때문입니다.
통합 형식이 지원하지 않는 스토리지 유형은 다음 가이드를 참고합니다.
| 오브젝트 스토리지 유형 | 통합 형식 지원 여부 |
|---|---|
| 백업 | ❌ |
| 컨테이너 레지스트리 (선택 기능) | ❌ |
| Mattermost | ❌ |
| Autoscale 러너 캐싱 (성능 향상을 위한 선택 사항) | ❌ |
| 보안 파일 | ✅ |
| Job 아티팩트 (아카이브된 job 로그 포함) | ✅ |
| LFS 오브젝트 | ✅ |
| 업로드 | ✅ |
| 머지 리퀘스트 diff | ✅ |
| 패키지 (선택 기능) | ✅ |
| Dependency Proxy (선택 기능) | ✅ |
| Terraform 상태 파일 | ✅ |
| Pages 콘텐츠 | ✅ |
연결 설정 구성#
통합 형식과 스토리지별 형식 모두 연결을 구성해야 합니다. 다음 섹션은 connection 설정에서 사용할 수 있는
매개변수를 설명합니다.
S3 호환 공급자#
이 설정은 AWS 연결 유형을 사용하는 Amazon S3 및 모든 S3 호환 서비스에 적용됩니다.
AWS를 직접 사용하지 않는 경우 endpoint를 공급자의 URL로 설정합니다.
S3 호환 서비스는 AWS S3 API를 구현하는 수준이 서로 다릅니다. GitLab은 사전 서명된 URL, 멀티파트 업로드, 선택적으로 청크 서명 스트리밍 등 특정 S3 동작을 사용하는데, 모든 S3 호환 구현이 이를 동일하게 지원하는 것은 아닙니다. 공급자가 다른 도구에서는 작동하지만 GitLab에서는 작동하지 않는다면, 조정이 필요할 가능성이 가장 큰 설정은 다음과 같습니다.
aws_signature_version.enable_signature_v4_streaming.
연결 설정은 fog-aws에서 제공하는 설정과 일치합니다.
| 설정 | 설명 | 기본값 |
|---|---|---|
provider |
호환 호스트에서는 항상 AWS입니다. |
AWS |
aws_access_key_id |
AWS 자격 증명 또는 호환 자격 증명입니다. | |
aws_secret_access_key |
AWS 자격 증명 또는 호환 자격 증명입니다. | |
aws_signature_version |
사용할 AWS 서명 버전입니다. 2 또는 4를 사용할 수 있습니다. 일부 S3 호환 공급자는 2가 필요할 수 있습니다. |
4 |
enable_signature_v4_streaming |
AWS v4 서명과 함께 HTTP 청크 전송을 활성화하려면 true로 설정합니다. 일부 S3 호환 공급자는 이 값이 false여야 합니다. GitLab 17.4에서 기본값이 true에서 false로 변경되었습니다. |
false |
region |
AWS 리전입니다. | |
host |
사용 중단됨: 대신 endpoint를 사용합니다. AWS를 사용하지 않을 때의 S3 호환 호스트입니다. 예: localhost 또는 storage.example.com. HTTPS와 포트 443을 가정합니다. |
s3.amazonaws.com |
endpoint |
http://127.0.0.1:9000과 같은 URL을 입력하여 S3 호환 서비스를 구성할 때 사용할 수 있습니다. host보다 우선합니다. 통합 형식에서는 항상 endpoint를 사용합니다. |
(선택 사항) |
path_style |
bucket_name.host/object 대신 host/bucket_name/object 형식의 경로를 사용하려면 true로 설정합니다. 경로 스타일 주소 지정이 필요한 S3 호환 서비스에서는 true로 설정합니다. AWS S3에서는 false로 둡니다. |
false |
use_iam_profile |
액세스 키 대신 IAM 프로파일을 사용하려면 true로 설정합니다. |
false |
aws_credentials_refresh_threshold_seconds |
IAM에서 임시 자격 증명을 사용할 때의 자동 갱신 임계값을 초 단위로 설정합니다. 정수여야 합니다. | 151 |
disable_imds_v2 |
X-aws-ec2-metadata-token을 가져오는 IMDS v2 엔드포인트에 대한 접근을 비활성화하여 IMDS v1 사용을 강제합니다. |
false |
S3 호환성 및 알려진 실패 모드#
S3 호환을 표방한다고 해서 공급자가 GitLab과 올바르게 작동한다는 보장은 없습니다. S3 호환 공급자에서 오류가 발생하면 지원 요청을 하기 전에 다음 조정을 시도합니다.
- 서명 스트리밍: 일부 공급자는 AWS Signature
Version 4 스트리밍에서 사용하는 청크 전송 인코딩을 거부합니다.
enable_signature_v4_streaming: false로 설정합니다. - 서명 버전: 일부 공급자는 Signature Version 4를 완전히 지원하지 않습니다.
aws_signature_version: 2로 설정합니다. - 경로 스타일 URL: 일부 공급자는 경로 스타일 버킷 주소 지정이 필요합니다.
path_style: true로 설정합니다. - ETag 검증: 일부 공급자는 업로드된 오브젝트의 MD5와 일치하지 않는 ETag를 반환하며, GitLab은 이를 검증합니다. ETag 불일치를 참고합니다.
GitLab 지원팀은 구성 문제 해결을 도울 수 있지만, 테스트된 공급자가 아닌 공급자에 국한된 문제의 해결은 보장할 수 없습니다.
Amazon 인스턴스 프로파일 사용#
오브젝트 스토리지 구성에 AWS 액세스 키와 시크릿 키를 제공하는 대신, GitLab이 Amazon Identity Access and Management(IAM) 역할을 사용하여 Amazon 인스턴스 프로파일을 설정하도록 구성할 수 있습니다. 이렇게 하면 GitLab은 S3 버킷에 접근할 때마다 임시 자격 증명을 가져오므로 구성에 하드 코딩된 값이 필요하지 않습니다.
사전 요구 사항:
- GitLab이 인스턴스 메타데이터 엔드포인트에 연결할 수 있어야 합니다.
- GitLab이 인터넷 프록시를 사용하도록 구성된 경우, 엔드포인트 IP
주소를
no_proxy목록에 추가해야 합니다. - IMDS v2 접근의 경우 홉 제한이 충분한지 확인합니다. GitLab이 컨테이너에서 실행되는 경우 제한을 1에서 2로 올려야 할 수 있습니다.
인스턴스 프로파일을 설정하려면 다음을 수행합니다.
-
필요한 권한이 있는 IAM 역할을 생성합니다. 다음은
test-bucket이라는 S3 버킷에 대한 역할의 예시입니다.{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:PutObject", "s3:GetObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::test-bucket/*" }, { "Effect": "Allow", "Action": [ "s3:ListBucket" ], "Resource": "arn:aws:s3:::test-bucket" } ] }[!note] 외부 프로세스가 S3 버킷의 오브젝트에 태그를 지정하는 경우(예: AWS GuardDuty Malware Protection), 소스 버킷의 오브젝트 수준
Action목록에s3:GetObjectTagging을 추가하고 대상 버킷에는s3:PutObjectTagging을 추가합니다. 이 권한이 없으면 태그가 지정된 오브젝트를 복사할 때 GitLabCopyObject작업이AccessDenied로 실패합니다. -
GitLab 인스턴스를 호스팅하는 EC2 인스턴스에 이 역할을 연결합니다.
-
use_iam_profileGitLab 구성 옵션을true로 설정합니다.
암호화된 S3 버킷#
인스턴스 프로파일 또는 통합 형식으로 구성하면, GitLab Workhorse는 SSE-S3 또는 SSE-KMS 암호화가 기본으로 활성화된 S3 버킷에 파일을 올바르게 업로드합니다. AWS KMS 키와 SSE-C 암호화는 모든 요청에 암호화 키를 전송해야 하므로 지원되지 않습니다.
서버 측 암호화 헤더#
S3 버킷에 기본 암호화를 설정하는 것이 암호화를 활성화하는
가장 쉬운 방법이지만,
암호화된 오브젝트만 업로드되도록 버킷 정책을 설정하고 싶을 수도 있습니다.
이렇게 하려면 storage_options 구성 섹션에서
적절한 암호화 헤더를 전송하도록 GitLab을 구성해야 합니다.
| 설정 | 설명 |
|---|---|
server_side_encryption |
암호화 모드(AES256 또는 aws:kms)입니다. |
server_side_encryption_kms_key_id |
Amazon 리소스 이름(ARN)입니다. server_side_encryption에서 aws:kms를 사용할 때만 필요합니다. KMS 암호화 사용에 관한 Amazon 문서를 참고합니다. |
기본 암호화의 경우와 마찬가지로, 이 옵션은 Workhorse S3 클라이언트가 활성화된 경우에만 작동합니다. 다음 두 조건 중 하나를 충족해야 합니다.
- 연결 설정에서
use_iam_profile이true입니다. - 통합 형식을 사용 중입니다.
Workhorse S3 클라이언트를 활성화하지 않고 서버 측 암호화 헤더를 사용하면 ETag 불일치 오류가 발생합니다.
Google Cloud Storage (GCS)#
히스토리
universe_domain설정이 GitLab 18.9에서 도입되었습니다.
GCS에 유효한 연결 매개변수는 다음과 같습니다.
| 설정 | 설명 | 예시 |
|---|---|---|
provider |
공급자 이름입니다. | Google |
google_project |
GCP 프로젝트 이름입니다. | gcp-project-12345 |
google_json_key_location |
JSON 키 경로입니다. | /path/to/gcp-project-12345-abcde.json |
google_json_key_string |
JSON 키 문자열입니다. | { "type": "service_account", "project_id": "example-project-382839", ... } |
google_application_default |
Google Cloud Application Default Credentials를 사용하여 서비스 계정 자격 증명을 찾으려면 true로 설정합니다. |
|
universe_domain |
Google Cloud 요청에 사용할 유니버스 도메인입니다. Google Cloud Dedicated 또는 기본값이 아닌 다른 유니버스 도메인에 연결할 때 사용합니다. | googleapis.com |
GitLab은 google_json_key_location, google_json_key_string, google_application_default 순서로 값을 읽습니다.
이 중 값이 있는 첫 번째 설정을 사용합니다.
서비스 계정에는 버킷에 접근할 권한이 있어야 합니다. 자세한 내용은 Cloud Storage 인증 문서를 참고합니다.
Google Cloud Application Default Credentials#
Google Cloud Application Default Credentials(ADC)는 일반적으로
GitLab에서 기본 서비스 계정이나 Workload Identity Federation을 사용하기 위해
쓰입니다. google_application_default를 true로 설정하고 google_json_key_location과 google_json_key_string은 생략합니다.
ADC를 사용하는 경우 다음을 확인합니다.
-
사용하는 서비스 계정에
iam.serviceAccounts.signBlob권한이 있어야 합니다. 일반적으로 서비스 계정에Service Account Token Creator역할을 부여하여 처리합니다. -
Google Compute 가상 머신을 사용하는 경우, Google Cloud API에 접근하기 위한 올바른 액세스 범위가 있는지 확인합니다. 머신에 올바른 범위가 없으면 오류 로그에 다음과 같이 표시될 수 있습니다.
Google::Apis::ClientError (insufficientPermissions: Request had insufficient authentication scopes.)
고객 관리 암호화 키로 버킷 암호화를 사용하려면 통합 형식을 사용합니다.
-
/etc/gitlab/gitlab.rb를 편집하고 다음 줄을 추가하되, 원하는 값으로 대체합니다.gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '', 'google_json_key_location' => '' }ADC를 사용하려면 대신
google_application_default를 사용합니다.gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '', 'google_application_default' => true }기본값이 아닌 유니버스 도메인(예: Google Cloud Dedicated)을 사용하려면 다음과 같이 설정합니다.
gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '', 'google_application_default' => true, 'universe_domain' => '' } -
파일을 저장하고 GitLab을 재구성합니다.
sudo gitlab-ctl reconfigure
-
다음 내용을
object_storage.yaml이라는 파일에 넣어 Kubernetes Secret으로 사용합니다.provider: Google google_project: PROJECT> google_json_key_location: ''ADC를 사용하려면 대신
google_application_default를 사용합니다.provider: Google google_project: PROJECT> google_application_default: true기본값이 아닌 유니버스 도메인(예: Google Cloud Dedicated)을 사용하려면 다음과 같이 설정합니다.
provider: Google google_project: PROJECT> google_application_default: true universe_domain: DOMAIN> -
Kubernetes Secret을 생성합니다.
kubectl create secret generic -n <namespace> gitlab-object-storage --from-file=connection=object_storage.yaml -
Helm 값을 내보냅니다.
helm get values gitlab > gitlab_values.yaml -
gitlab_values.yaml을 편집합니다.global: appConfig: artifacts: bucket: gitlab-artifacts ciSecureFiles: bucket: gitlab-ci-secure-files enabled: true dependencyProxy: bucket: gitlab-dependency-proxy enabled: true externalDiffs: bucket: gitlab-mr-diffs enabled: true lfs: bucket: gitlab-lfs object_store: connection: secret: gitlab-object-storage enabled: true proxy_download: false packages: bucket: gitlab-packages terraformState: bucket: gitlab-terraform-state enabled: true uploads: bucket: gitlab-uploads -
파일을 저장하고 새 값을 적용합니다.
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
-
docker-compose.yml을 편집합니다.version: "3.6" services: gitlab: environment: GITLAB_OMNIBUS_CONFIG: | # Consolidated object storage configuration gitlab_rails['object_store']['enabled'] = true gitlab_rails['object_store']['proxy_download'] = false gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '', 'google_json_key_location' => '' } gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'ADC를 사용하려면 대신
google_application_default를 사용합니다.gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '', 'google_application_default' => true }기본값이 아닌 유니버스 도메인(예: Google Cloud Dedicated)을 사용하려면 다음과 같이 설정합니다.
gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '', 'google_application_default' => true, 'universe_domain' => '' } -
파일을 저장하고 GitLab을 다시 시작합니다.
docker compose up -d
Azure Blob storage#
Azure는 블롭 모음을 가리키는 데 container라는 단어를 사용하지만,
GitLab은 bucket이라는 용어로 통일합니다. Azure
컨테이너 이름은 반드시 bucket 설정에 구성합니다.
Azure Blob storage는 여러 컨테이너에 접근하는 데 단일 자격 증명 집합을 사용하므로 통합 형식에서만 사용할 수 있습니다. 스토리지별 형식은 지원되지 않습니다. 자세한 내용은 통합 형식으로 전환하는 방법을 참고합니다.
다음은 Azure에 유효한 연결 매개변수입니다. 자세한 내용은 Azure Blob Storage 문서를 참고합니다.
| 설정 | 설명 | 예시 |
|---|---|---|
provider |
공급자 이름입니다. | AzureRM |
azure_storage_account_name |
스토리지에 접근하는 데 사용하는 Azure Blob Storage 계정의 이름입니다. | azuretest |
azure_storage_access_key |
컨테이너에 접근하는 데 사용하는 스토리지 계정 액세스 키입니다. 일반적으로 base64로 인코딩된 512비트 시크릿 암호화 키입니다. Azure 워크로드 및 관리형 ID에서는 선택 사항입니다. | czV2OHkvQj9FKEgrTWJRZVRoV21ZcTN0Nnc5eiRDJkYpSkBOY1JmVWpYbjJy\nNHU3eCFBJUQqRy1LYVBkU2dWaw==\n |
azure_storage_domain |
Azure Blob Storage API에 접속하는 데 사용하는 도메인 이름입니다(선택 사항). 기본값은 blob.core.windows.net입니다. Azure China, Azure Germany, Azure US Government 또는 그 밖의 사용자 지정 Azure 도메인을 사용하는 경우 설정합니다. |
blob.core.windows.net |
-
/etc/gitlab/gitlab.rb를 편집하고 다음 줄을 추가하되, 원하는 값으로 대체합니다.gitlab_rails['object_store']['connection'] = { 'provider' => 'AzureRM', 'azure_storage_account_name' => '', 'azure_storage_access_key' => '', 'azure_storage_domain' => '' } gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'워크로드 ID를 사용하는 경우
azure_storage_access_key를 생략합니다.gitlab_rails['object_store']['connection'] = { 'provider' => 'AzureRM', 'azure_storage_account_name' => '', 'azure_storage_domain' => '' } -
파일을 저장하고 GitLab을 재구성합니다.
sudo gitlab-ctl reconfigure
-
다음 내용을
object_storage.yaml이라는 파일에 넣어 Kubernetes Secret으로 사용합니다.provider: AzureRM azure_storage_account_name: azure_storage_access_key: azure_storage_domain: blob.core.windows.net워크로드 ID 또는 관리형 ID를 사용하는 경우
azure_storage_access_key를 생략합니다.provider: AzureRM azure_storage_account_name: azure_storage_domain: blob.core.windows.net -
Kubernetes Secret을 생성합니다.
kubectl create secret generic -n <namespace> gitlab-object-storage --from-file=connection=object_storage.yaml -
Helm 값을 내보냅니다.
helm get values gitlab > gitlab_values.yaml -
gitlab_values.yaml을 편집합니다.global: appConfig: artifacts: bucket: gitlab-artifacts ciSecureFiles: bucket: gitlab-ci-secure-files enabled: true dependencyProxy: bucket: gitlab-dependency-proxy enabled: true externalDiffs: bucket: gitlab-mr-diffs enabled: true lfs: bucket: gitlab-lfs object_store: connection: secret: gitlab-object-storage enabled: true proxy_download: false packages: bucket: gitlab-packages terraformState: bucket: gitlab-terraform-state enabled: true uploads: bucket: gitlab-uploads -
파일을 저장하고 새 값을 적용합니다.
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
-
docker-compose.yml을 편집합니다.version: "3.6" services: gitlab: environment: GITLAB_OMNIBUS_CONFIG: | # Consolidated object storage configuration gitlab_rails['object_store']['enabled'] = true gitlab_rails['object_store']['proxy_download'] = false gitlab_rails['object_store']['connection'] = { 'provider' => 'AzureRM', 'azure_storage_account_name' => '', 'azure_storage_access_key' => '', 'azure_storage_domain' => '' } gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'관리형 ID를 사용하는 경우
azure_storage_access_key를 생략합니다.gitlab_rails['object_store']['connection'] = { 'provider' => 'AzureRM', 'azure_storage_account_name' => '', 'azure_storage_domain' => '' } -
파일을 저장하고 GitLab을 다시 시작합니다.
docker compose up -d
자체 컴파일 설치에서는 Workhorse에도 Azure 자격 증명을 구성해야 합니다. Linux 패키지 설치에서는 Workhorse 설정이 앞의 설정에서 채워지므로 이 구성이 필요하지 않습니다.
-
/home/git/gitlab/config/gitlab.yml을 편집하고 다음 줄을 추가하거나 수정합니다.production: &base object_store: enabled: true proxy_download: false connection: provider: AzureRM azure_storage_account_name: '' azure_storage_access_key: '' objects: artifacts: bucket: gitlab-artifacts external_diffs: bucket: gitlab-mr-diffs lfs: bucket: gitlab-lfs uploads: bucket: gitlab-uploads packages: bucket: gitlab-packages dependency_proxy: bucket: gitlab-dependency-proxy terraform_state: bucket: gitlab-terraform-state ci_secure_files: bucket: gitlab-ci-secure-files pages: bucket: gitlab-pages -
/home/git/gitlab-workhorse/config.toml을 편집하고 다음 줄을 추가하거나 수정합니다.[object_storage] provider = "AzureRM" [object_storage.azurerm] azure_storage_account_name = "" azure_storage_access_key = ""사용자 지정 Azure 스토리지 도메인을 사용하는 경우 Workhorse 구성에는
azure_storage_domain을 설정하지 않아도 됩니다. 이 정보는 GitLab Rails와 Workhorse 간의 API 호출로 교환됩니다. -
파일을 저장하고 GitLab을 다시 시작합니다.
# For systems running systemd sudo systemctl restart gitlab.target # For systems running SysV init sudo service gitlab restart
Azure 워크로드 및 관리형 ID#
히스토리
- GitLab 17.9에서 도입되었습니다.
Azure 워크로드 ID 또는 관리형 ID를 사용하려면 구성에서
azure_storage_access_key를 생략합니다.
azure_storage_access_key가 비어 있으면 GitLab은 다음을 시도합니다.
- 워크로드 ID로 임시 자격 증명을 가져옵니다. 환경에
AZURE_TENANT_ID,AZURE_CLIENT_ID,AZURE_FEDERATED_TOKEN_FILE이 있어야 합니다. - 워크로드 ID를 사용할 수 없으면 Azure Instance Metadata Service에 자격 증명을 요청합니다.
- User Delegation Key를 가져옵니다.
- 해당 키로 SAS 토큰을 생성하여 Storage Account 블롭에 접근합니다.
ID에 Storage Blob Data Contributor 역할이
할당되어 있는지 확인합니다.
공급자별 구성 예시#
다음 예시는 기본값이 아닌 설정이 필요한 특정 S3 호환 공급자의 구성을 보여줍니다.
여기에 나열되지 않은 S3 호환 공급자는
기본 S3 호환 구성을 사용하고 공급자에 맞는 endpoint를 지정합니다.
Oracle Cloud Infrastructure#
Oracle Cloud Infrastructure S3에는 다음 설정이 필요합니다.
| 설정 | 값 |
|---|---|
enable_signature_v4_streaming |
false |
path_style |
true |
enable_signature_v4_streaming을 true로 설정하면 production.log에
다음 오류가 표시될 수 있습니다.
STREAMING-AWS4-HMAC-SHA256-PAYLOAD is not supported
Storj Gateway (SJ)#
Storj Gateway는 멀티스레드 복사를 지원하지 않습니다(표의 UploadPartCopy 참고).
구현이 계획되어 있지만, 완료될 때까지는 멀티스레드 복사를 비활성화해야 합니다.
Storj Network는 S3 호환 API 게이트웨이를 제공합니다. 다음 구성 예시를 사용합니다.
gitlab_rails['object_store']['connection'] = {
'provider' => 'AWS',
'endpoint' => 'https://gateway.storjshare.io',
'path_style' => true,
'region' => 'eu1',
'aws_access_key_id' => 'ACCESS_KEY',
'aws_secret_access_key' => 'SECRET_KEY',
'aws_signature_version' => 2,
'enable_signature_v4_streaming' => false
}
서명 버전은 2여야 합니다. v4를 사용하면 HTTP 411 Length Required 오류가 발생합니다.
자세한 내용은 이슈 #4419를 참고합니다.
Hitachi Vantara HCP#
HCP에 연결하면 SignatureDoesNotMatch - The request signature we calculated does not match the signature you provided. Check your HCP Secret Access key and signing method.라는 오류가 반환될 수 있습니다. 이 경우 endpoint를 네임스페이스가 아닌 테넌트의 URL로 설정하고, 버킷 경로를 <namespace_name>/<bucket_name> 형식으로 구성했는지 확인합니다.
HCP는 S3 호환 API를 제공합니다. 다음 구성 예시를 사용합니다.
gitlab_rails['object_store']['connection'] = {
'provider' => 'AWS',
'endpoint' => 'https://<tenant_endpoint>',
'path_style' => true,
'region' => 'eu1',
'aws_access_key_id' => 'ACCESS_KEY',
'aws_secret_access_key' => 'SECRET_KEY',
'aws_signature_version' => 4,
'enable_signature_v4_streaming' => false
}
# Example of <namespace_name/bucket_name> formatting
gitlab_rails['object_store']['objects']['artifacts']['bucket'] = '<namespace_name>/<bucket_name>'
Ceph RGW#
Ceph RGW는 Ceph용 S3 호환 API입니다. 다음 구성 예시를 사용합니다.
gitlab_rails['object_store']['connection'] = {
'provider' => 'AWS',
'endpoint' => 'https://rgw-ceph.example.com',
'region' => 'us-west-1',
'aws_access_key_id' => 'ACCESS_KEY',
'aws_secret_access_key' => 'SECRET_KEY',
'path_style': true
}
Ceph RGW에서 서버 측 암호화를 활성화하려면 HTTPS로 연결해야 합니다. Ceph는 보안되지 않은 연결을 통한 암호화 요청을 거부합니다.
통합 형식 및 Amazon S3를 사용하는 전체 예시#
다음 예시는 AWS S3를 사용하여 지원되는 모든 서비스에 오브젝트 스토리지를 활성화합니다.
-
/etc/gitlab/gitlab.rb를 편집하고 다음 줄을 추가하되, 원하는 값으로 대체합니다.# Consolidated object storage configuration gitlab_rails['object_store']['enabled'] = true gitlab_rails['object_store']['proxy_download'] = false gitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', 'region' => 'eu-central-1', 'aws_access_key_id' => '', 'aws_secret_access_key' => '' } # OPTIONAL: The following lines are only needed if server side encryption is required gitlab_rails['object_store']['storage_options'] = { 'server_side_encryption' => '', 'server_side_encryption_kms_key_id' => '<arn:aws:kms:xxx>' } gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'AWS IAM 프로파일을 사용하는 경우 AWS 액세스 키와 시크릿 액세스 키 키/값 쌍을 생략합니다. 예를 들면 다음과 같습니다.
gitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', 'region' => 'eu-central-1', 'use_iam_profile' => true } -
파일을 저장하고 GitLab을 재구성합니다.
sudo gitlab-ctl reconfigure
-
다음 내용을
object_storage.yaml이라는 파일에 넣어 Kubernetes Secret으로 사용합니다.provider: AWS region: us-east-1 aws_access_key_id: aws_secret_access_key:AWS IAM 프로파일을 사용하는 경우 AWS 액세스 키와 시크릿 액세스 키 키/값 쌍을 생략합니다. 예를 들면 다음과 같습니다.
provider: AWS region: us-east-1 use_iam_profile: true -
Kubernetes Secret을 생성합니다.
kubectl create secret generic -n <namespace> gitlab-object-storage --from-file=connection=object_storage.yaml -
Helm 값을 내보냅니다.
helm get values gitlab > gitlab_values.yaml -
gitlab_values.yaml을 편집합니다.global: appConfig: artifacts: bucket: gitlab-artifacts ciSecureFiles: bucket: gitlab-ci-secure-files enabled: true dependencyProxy: bucket: gitlab-dependency-proxy enabled: true externalDiffs: bucket: gitlab-mr-diffs enabled: true lfs: bucket: gitlab-lfs object_store: connection: secret: gitlab-object-storage enabled: true proxy_download: false packages: bucket: gitlab-packages terraformState: bucket: gitlab-terraform-state enabled: true uploads: bucket: gitlab-uploads -
파일을 저장하고 새 값을 적용합니다.
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
-
docker-compose.yml을 편집합니다.version: "3.6" services: gitlab: environment: GITLAB_OMNIBUS_CONFIG: | # Consolidated object storage configuration gitlab_rails['object_store']['enabled'] = true gitlab_rails['object_store']['proxy_download'] = false gitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', 'region' => 'eu-central-1', 'aws_access_key_id' => '', 'aws_secret_access_key' => '' } # OPTIONAL: The following lines are only needed if server side encryption is required gitlab_rails['object_store']['storage_options'] = { 'server_side_encryption' => '', 'server_side_encryption_kms_key_id' => '<arn:aws:kms:xxx>' } gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'AWS IAM 프로파일을 사용하는 경우 AWS 액세스 키와 시크릿 액세스 키 키/값 쌍을 생략합니다. 예를 들면 다음과 같습니다.
gitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', 'region' => 'eu-central-1', 'use_iam_profile' => true } -
파일을 저장하고 GitLab을 다시 시작합니다.
docker compose up -d
-
/home/git/gitlab/config/gitlab.yml을 편집하고 다음 줄을 추가하거나 수정합니다.production: &base object_store: enabled: true proxy_download: false connection: provider: AWS aws_access_key_id: aws_secret_access_key: region: eu-central-1 storage_options: server_side_encryption: or aws:kms> server_side_encryption_key_kms_id: <arn:aws:kms:xxx> objects: artifacts: bucket: gitlab-artifacts external_diffs: bucket: gitlab-mr-diffs lfs: bucket: gitlab-lfs uploads: bucket: gitlab-uploads packages: bucket: gitlab-packages dependency_proxy: bucket: gitlab-dependency-proxy terraform_state: bucket: gitlab-terraform-state ci_secure_files: bucket: gitlab-ci-secure-files pages: bucket: gitlab-pagesAWS IAM 프로파일을 사용하는 경우 AWS 액세스 키와 시크릿 액세스 키 키/값 쌍을 생략합니다. 예를 들면 다음과 같습니다.
connection: provider: AWS region: eu-central-1 use_iam_profile: true -
/home/git/gitlab-workhorse/config.toml을 편집하고 다음 줄을 추가하거나 수정합니다.[object_storage] provider = "AWS" [object_storage.s3] aws_access_key_id = "" aws_secret_access_key = ""AWS IAM 프로파일을 사용하는 경우 AWS 액세스 키와 시크릿 액세스 키 키/값 쌍을 생략합니다. 예를 들면 다음과 같습니다.
[object_storage.s3] use_iam_profile = true -
파일을 저장하고 GitLab을 다시 시작합니다.
# For systems running systemd sudo systemctl restart gitlab.target # For systems running SysV init sudo service gitlab restart
오브젝트 스토리지로 마이그레이션#
기존 로컬 데이터를 오브젝트 스토리지로 마이그레이션하려면 다음 가이드를 참고합니다.
- Job 아티팩트 (아카이브된 job 로그 포함)
- LFS 오브젝트
- 업로드
- 머지 리퀘스트 diff
- 패키지 (선택 기능)
- Dependency Proxy
- Terraform 상태 파일
- Pages 콘텐츠
- 프로젝트 수준 보안 파일
통합 형식으로 전환#
스토리지별 구성에서는 다음과 같이 동작합니다.
- CI/CD 아티팩트, LFS 파일, 업로드 첨부 파일 등 모든 유형의 오브젝트에 대한 오브젝트 스토리지 구성이 각각 독립적으로 이루어집니다.
- 비밀번호와 엔드포인트 URL 같은 오브젝트 스토어 연결 매개변수가 유형마다 중복됩니다.
예를 들어 Linux 패키지 설치에는 다음과 같은 구성이 있을 수 있습니다.
# Original object storage configuration
gitlab_rails['artifacts_object_store_enabled'] = true
gitlab_rails['artifacts_object_store_direct_upload'] = true
gitlab_rails['artifacts_object_store_proxy_download'] = false
gitlab_rails['artifacts_object_store_remote_directory'] = 'artifacts'
gitlab_rails['artifacts_object_store_connection'] = { 'provider' => 'AWS', 'aws_access_key_id' => 'access_key', 'aws_secret_access_key' => 'secret' }
gitlab_rails['uploads_object_store_enabled'] = true
gitlab_rails['uploads_object_store_direct_upload'] = true
gitlab_rails['uploads_object_store_proxy_download'] = false
gitlab_rails['uploads_object_store_remote_directory'] = 'uploads'
gitlab_rails['uploads_object_store_connection'] = { 'provider' => 'AWS', 'aws_access_key_id' => 'access_key', 'aws_secret_access_key' => 'secret' }
이 방식은 GitLab이 서로 다른 클라우드 공급자에 걸쳐 오브젝트를 저장할 수 있다는 유연성을 제공하지만, 그만큼 복잡성이 늘어나고 불필요한 중복도 생깁니다. GitLab Rails와 Workhorse 구성 요소 모두 오브젝트 스토리지에 접근해야 하므로, 통합 형식은 자격 증명이 과도하게 중복되는 것을 피합니다.
통합 형식은 기존 형식의 모든 줄을
생략한 경우에만 사용됩니다. 통합 형식으로 전환하려면
기존 구성(예: artifacts_object_store_enabled 또는
uploads_object_store_connection)을 제거합니다.
다른 오브젝트 스토리지 공급자로 오브젝트 마이그레이션#
오브젝트 스토리지에 있는 GitLab 데이터를 다른 오브젝트 스토리지 공급자로 마이그레이션해야 할 수 있습니다. 다음 단계는 Rclone을 사용하여 이를 수행하는 방법을 보여줍니다.
이 단계는 uploads 버킷을 옮기는 것을 가정하지만, 다른 버킷에도 같은 절차가 적용됩니다.
사전 요구 사항:
- Rclone을 실행할 컴퓨터를 선택합니다. 마이그레이션하는 데이터 양에 따라 Rclone을 오랫동안 실행해야 할 수 있으므로 절전 모드로 전환될 수 있는 노트북이나 데스크톱 컴퓨터는 피합니다. GitLab 서버에서 Rclone을 실행해도 됩니다.
-
Rclone을 설치합니다.
-
다음을 실행하여 Rclone을 구성합니다.
rclone config구성 과정은 대화형입니다. 최소 두 개의 "remote"를 추가합니다. 하나는 데이터가 현재 있는 오브젝트 스토리지 공급자(
old)용이고, 다른 하나는 이전할 공급자(new)용입니다. -
이전 데이터를 읽을 수 있는지 확인합니다. 다음 예시는
uploads버킷을 기준으로 하지만, 사용 중인 버킷의 이름은 다를 수 있습니다.rclone ls old:uploads | head현재
uploads버킷에 저장된 오브젝트의 일부 목록이 출력되어야 합니다. 오류가 발생하거나 목록이 비어 있으면, 돌아가서rclone config로 Rclone 구성을 업데이트합니다. -
초기 복사를 수행합니다. 이 단계에서는 GitLab 서버를 오프라인으로 전환할 필요가 없습니다.
rclone sync -P old:uploads new:uploads -
첫 번째 동기화가 완료되면 새 오브젝트 스토리지 공급자의 웹 UI 또는 명령줄 인터페이스를 사용하여 새 버킷에 오브젝트가 있는지 확인합니다. 오브젝트가 없거나
rclone sync를 실행하는 동안 오류가 발생하면 Rclone 구성을 확인하고 다시 시도합니다.
이전 위치에서 새 위치로 Rclone 복사를 한 번 이상 성공적으로 수행한 후에는 유지 관리 일정을 잡고 GitLab 서버를 오프라인으로 전환합니다. 유지 관리 시간 동안 다음 두 가지를 수행해야 합니다.
- 사용자가 새 오브젝트를 추가할 수 없으므로 이전 버킷에 남는 오브젝트가 없다는 점을 확인하고, 마지막
rclone sync를 실행합니다. uploads에 새 공급자를 사용하도록 GitLab 서버의 오브젝트 스토리지 구성을 업데이트합니다.
파일 시스템 스토리지 대안#
GitLab 구현을 스케일 아웃하거나 내결함성과 이중화를 추가하려는 경우, 블록 또는 네트워크 파일 시스템에 대한 의존성을 제거하는 방안을 검토하고 있을 수 있습니다. 다음 추가 가이드를 참고합니다.
git사용자 홈 디렉터리가 로컬 디스크에 있는지 확인합니다.- 공유
authorized_keys파일이 필요하지 않도록 SSH 키의 데이터베이스 조회를 구성합니다. - job 로그의 로컬 디스크 사용을 방지합니다.
- Pages 로컬 스토리지를 비활성화합니다.
문제 해결#
오브젝트가 GitLab 백업에 포함되지 않음#
백업 문서에 나와 있듯이 오브젝트는 GitLab 백업에 포함되지 않습니다. 대신 오브젝트 스토리지 공급자에서 백업을 활성화할 수 있습니다.
별도의 버킷 사용#
데이터 유형마다 별도의 버킷을 사용하는 것이 GitLab에서 권장하는 방식입니다. 이렇게 하면 GitLab이 저장하는 여러 데이터 유형 간에 충돌이 발생하지 않습니다. 이슈 292958은 단일 버킷을 사용할 수 있도록 하는 방안을 제안합니다.
Linux 패키지 설치와 자체 컴파일 설치에서는 하나의 실제
버킷을 여러 가상 버킷으로 나눌 수 있습니다. 오브젝트 스토리지
버킷 이름이 my-gitlab-objects라면 업로드는
my-gitlab-objects/uploads로, 아티팩트는
my-gitlab-objects/artifacts로 저장되도록 구성할 수 있습니다.
애플리케이션은 이를 별도의 버킷인 것처럼 동작합니다. 버킷 접두사 사용은
Helm 백업에서 올바르게 작동하지 않을 수 있습니다.
Helm 기반 설치에서는 백업 복원을 처리하려면 별도의 버킷이 필요합니다.
S3 API 호환성 문제#
S3 호환 공급자에서 오류가 발생하면
일반적인 원인과 구성 조정 방법은
S3 호환성 및 알려진 실패 모드를 참고합니다.
production.log의 411 Length Required 오류는 일반적으로 서명 스트리밍이 원인입니다.
enable_signature_v4_streaming: false로 설정하여 해결합니다.
아티팩트가 항상 파일명 download로 다운로드됨#
다운로드되는 아티팩트의 파일명은
GetObject 요청의 response-content-disposition 헤더로 설정됩니다.
S3 공급자가 이 헤더를 지원하지 않으면 다운로드된 파일은 항상 download로 저장됩니다.
프록시 다운로드#
클라이언트는 사전 서명된 시간 제한 URL을 받아 오브젝트 스토리지의 파일을 다운로드하거나, GitLab이 오브젝트 스토리지의 데이터를 클라이언트로 프록시하는 방식으로 다운로드할 수 있습니다. 오브젝트 스토리지에서 파일을 직접 다운로드하면 GitLab이 처리해야 하는 이그레스 트래픽의 양을 줄일 수 있습니다.
파일이 로컬 블록 스토리지나 NFS에 저장된 경우 GitLab이 프록시 역할을 해야 합니다. 오브젝트 스토리지에서는 이것이 기본 동작이 아닙니다.
proxy_download 설정이 이 동작을 제어하며 기본값은 false입니다.
각 사용 사례의 문서에서 이를 확인합니다.
GitLab이 파일을 프록시하도록 하려면 proxy_download를 true로 설정합니다.
proxy_download를 true로 설정하면 GitLab 서버의 성능이 크게 저하될 수 있습니다. GitLab의 서버 배포에서는 proxy_download가 false로 설정되어 있습니다.
프록시 다운로드에 대한 클라이언트 재정의 허용#
히스토리
- GitLab 19.4에서 도입되었습니다.
기본적으로 모든 다운로드는 proxy_download로 설정된 전송 모드를 사용하며 API 클라이언트는 이를 재정의할 수 없습니다.
API 클라이언트가 지원되는 엔드포인트에서 다른 전송 모드를 선택할 수 있도록 하려면 allowed_download_modes를
proxy와 direct를 모두 포함하는 목록으로 설정합니다. 예를 들면 다음과 같습니다.
object_store:
proxy_download: true
allowed_download_modes: [proxy, direct]
allowed_download_modes에 direct가 포함되면, 클라이언트는 지원되는 엔드포인트에서 download_mode=direct를 쿼리 매개변수로 전달하여
GitLab을 통해 요청을 프록시하는 대신 오브젝트 스토리지로 향하는 HTTP 302 리디렉션을 받을 수 있습니다.
엔드포인트가 직접 다운로드를 지원하지 않거나 클라이언트가 매개변수를 보내지 않으면
GitLab은 proxy_download로 설정된 모드를 사용합니다.
allowed_download_modes는 proxy, direct 또는 둘 다만 포함하는 배열이어야 합니다. 이 값이
일반 문자열(예: allowed_download_modes: [proxy] 대신 allowed_download_modes: proxy)이거나
다른 값을 포함하면 GitLab이 시작되지 않습니다.
proxy_download를 false로 설정하면 GitLab은
사전 서명된 시간 제한 오브젝트 스토리지 URL이 포함된 HTTP 302 리디렉션을 반환합니다.
이로 인해 다음과 같은 문제가 발생할 수 있습니다.
-
GitLab이 보안되지 않은 HTTP로 오브젝트 스토리지에 접근하는 경우, 클라이언트가
https->http다운그레이드 오류를 발생시키고 리디렉션 처리를 거부할 수 있습니다. 해결 방법은 GitLab이 HTTPS를 사용하는 것입니다. 예를 들어 LFS에서는 다음 오류가 발생합니다.LFS: lfsapi/client: refusing insecure redirect, https->http -
클라이언트는 오브젝트 스토리지 인증서를 발급한 인증 기관을 신뢰해야 하며, 그렇지 않으면 다음과 같은 일반적인 TLS 오류가 반환될 수 있습니다.
x509: certificate signed by unknown authority -
클라이언트는 오브젝트 스토리지에 네트워크로 접근할 수 있어야 합니다. 네트워크 방화벽이 접근을 차단할 수 있습니다. 이 접근이 없을 때 발생할 수 있는 오류는 다음과 같습니다.
Received status code 403 from server: Forbidden -
오브젝트 스토리지 버킷은 GitLab 인스턴스의 URL에서 오는 교차 출처 리소스 공유 (CORS) 접근을 허용해야 합니다. 리포지터리 페이지에서 PDF를 로드하려고 하면 다음 오류가 표시될 수 있습니다.
An error occurred while loading the file. Please try again later.자세한 내용은 LFS 문서를 참고합니다.
사전 서명된 URL은 시간 제한이 있지만 특정 사용자에게 묶여 있지 않습니다. 사전 서명된 URL을 얻은 사용자는 누구나 URL이 유효한 동안 인증 없이 오브젝트에 접근할 수 있습니다. 직접 다운로드는 오브젝트 스토리지 공급자와 클라이언트 간에 대역폭 요금이 발생할 수도 있습니다.
ETag 불일치#
기본 GitLab 설정을 사용하면 Alibaba와 같은
일부 S3 호환 오브젝트 스토리지 백엔드에서
ETag mismatch 오류가 발생할 수 있습니다.
Amazon S3 암호화#
Amazon Web Services S3에서 이 ETag 불일치 오류가 표시된다면 버킷의 암호화 설정이 원인일 가능성이 큽니다. 이 문제를 해결하는 방법은 두 가지입니다.
S3 호환 서비스에는 통합 형식을 권장합니다. 일부 서비스는 ETag 불일치 오류를 해결하기 위해 호환 모드 활성화 같은 추가 서버 측 구성이 필요할 수도 있습니다.
통합 형식이나 인스턴스 프로파일을 활성화하지 않으면
GitLab Workhorse는 Content-MD5 HTTP 헤더가 계산되지 않은
사전 서명된 URL로 파일을 S3에 업로드합니다. 데이터가
손상되지 않도록 Workhorse는 전송한 데이터의 MD5 해시가
S3 서버가 반환한 ETag 헤더와 같은지 확인합니다. 암호화가
활성화되어 있으면 이 값이 같지 않으므로 Workhorse가 업로드 중에 ETag mismatch
오류를 보고합니다.
통합 형식이 다음과 같은 경우입니다.
- S3 호환 오브젝트 스토리지 또는 인스턴스 프로파일과 함께 사용되면, Workhorse는
S3 자격 증명을 가진 내부 S3 클라이언트를 사용하여
Content-MD5헤더를 계산할 수 있습니다. 따라서 S3 서버가 반환한 ETag 헤더를 비교할 필요가 없습니다. - S3 호환 오브젝트 스토리지와 함께 사용되지 않으면, Workhorse는 사전 서명된 URL을 사용하는 방식으로 되돌아갑니다.
Google Cloud Storage 암호화#
Google Cloud Storage(GCS)에서도 고객 관리 암호화 키(CMEK)를 사용한 데이터 암호화를 활성화하면 ETag 불일치 오류가 발생합니다.
CMEK를 사용하려면 통합 형식을 사용합니다.
멀티스레드 복사#
GitLab은 S3 Upload Part Copy API를 사용하여 버킷 내 파일 복사 속도를 높입니다. 일부 S3 호환 공급자는 이 기능을 지원하지 않으며 업로드 중 404 오류를 반환합니다.
멀티스레드 복사를 비활성화하려면 Rails 콘솔 접근 권한이 있는 GitLab 관리자에게 다음 명령을 실행하도록 요청합니다.
Feature.disable(:s3_multithreaded_uploads)
Rails Console을 통한 수동 테스트#
잘못된 구성이 의심될 때 이 방법으로 오브젝트 스토리지 연결을 확인합니다. 다음 예시는 연결을 테스트하고, 테스트 오브젝트를 쓴 다음, 다시 읽습니다.
-
Rails 콘솔을 시작합니다.
-
/etc/gitlab/gitlab.rb에 설정한 것과 같은 매개변수를 사용하여 다음 예시 형식으로 오브젝트 스토리지 연결을 설정합니다.기존 uploads 구성을 사용하는 연결 예시:
settings = Gitlab.config.uploads.object_store.connection.deep_symbolize_keys connection = Fog::Storage.new(settings)액세스 키를 사용하는 연결 예시:
connection = Fog::Storage.new( { provider: 'AWS', region: 'eu-central-1', aws_access_key_id: '', aws_secret_access_key: '' } )AWS IAM 프로파일을 사용하는 연결 예시:
connection = Fog::Storage.new( { provider: 'AWS', use_iam_profile: true, region: 'us-east-1' } ) -
테스트할 버킷 이름을 지정하고, 테스트 파일을 쓴 다음 마지막으로 읽습니다.
dir = connection.directories.new(key: '<bucket-name-here>') f = dir.files.create(key: 'test.txt', body: 'test') pp f pp dir.files.head('test.txt')
추가 디버깅 활성화#
히스토리
AWS_DEBUG환경 변수 지원이 GitLab 18.3에서 도입되었습니다.
HTTP 요청을 확인하기 위해 추가 디버깅을 활성화할 수도 있습니다. 로그 파일에 자격 증명이 유출되지 않도록 Rails 콘솔에서 수행해야 합니다. 다음은 공급자별로 요청 디버깅을 활성화하는 방법입니다.
EXCON_DEBUG 환경 변수를 설정합니다.
ENV['EXCON_DEBUG'] = "1"
AWS_DEBUG 환경 변수를 1로 설정하면 GitLab
Workhorse 로그에 S3 HTTP 요청 및 응답 헤더 로깅도 활성화할 수 있습니다.
Linux 패키지(Omnibus)의 경우:
-
/etc/gitlab/gitlab.rb를 편집하고 다음 줄을 추가합니다.gitlab_workhorse['env'] = { 'AWS_DEBUG' => '1' } -
파일을 저장하고 GitLab을 재구성합니다.
sudo gitlab-ctl reconfigureS3 호환 스토리지의 요청 및 응답 헤더는
/var/log/gitlab/gitlab-workhorse/current에 기록됩니다.
로거가 STDOUT으로 로그를 출력하도록 구성합니다.
Google::Apis.logger = Logger::new(STDOUT)
DEBUG 환경 변수를 설정합니다.
ENV['DEBUG'] = "1"
Geo 추적 데이터베이스를 초기화하여 오브젝트 일관성 확보#
다음과 같은 Geo 시나리오를 가정합니다.
- 환경이 Geo 기본 사이트와 보조 사이트로 구성되어 있습니다.
- 기본 사이트에서 오브젝트 스토리지로 마이그레이션했습니다.
- 보조 사이트는 별도의 오브젝트 스토리지 버킷을 사용합니다.
- Allow this secondary site to replicate content on Object Storage가 활성화되어 있습니다.
이러한 마이그레이션은 오브젝트가 실제로는 오브젝트 스토리지에 없는데도 추적 데이터베이스에서 동기화된 것으로 표시되게 할 수 있습니다. 이 경우 마이그레이션 후에도 오브젝트 상태가 일관되게 유지되도록 Geo 보조 사이트 복제를 초기화합니다.
오브젝트 스토리지로 마이그레이션 후 불일치#
로컬 스토리지에서 오브젝트 스토리지로 마이그레이션할 때 데이터 불일치가 발생할 수 있습니다. 특히 Geo와 함께 사용하면서 마이그레이션 전에 파일을 수동으로 삭제한 경우에 그렇습니다.
예를 들어 인스턴스 관리자가 로컬 파일 시스템에서 여러 아티팩트를 수동으로 삭제합니다. 이러한 변경 사항은 데이터베이스에 제대로 전파되지 않아 불일치가 발생합니다. 오브젝트 스토리지로 마이그레이션한 후에도 이 불일치는 그대로 남아 문제를 일으킬 수 있습니다. Geo 보조 사이트는 해당 파일이 데이터베이스에서 여전히 참조되지만 더 이상 존재하지 않는데도 계속 복제를 시도할 수 있습니다.
Geo를 사용할 때 불일치 식별#
다음과 같은 Geo 시나리오를 가정합니다.
- 환경이 Geo 기본 노드와 보조 노드로 구성되어 있습니다.
- 두 시스템 모두 오브젝트 스토리지로 마이그레이션되었습니다.
- 보조 노드는 기본 노드와 같은 오브젝트 스토리지를 사용합니다.
Allow this secondary site to replicate content on Object Storage옵션이 비활성화되어 있습니다.
- 오브젝트 스토리지 마이그레이션 전에 여러 업로드를 수동으로 삭제했습니다.
- 이 예시에서는 이슈에 업로드된 이미지 두 개입니다.
이러한 시나리오에서는 보조 노드가 기본 노드와 같은 오브젝트 스토리지를 사용하므로 더 이상 데이터를 복제할 필요가 없습니다. 불일치 때문에 관리자는 보조 노드가 여전히 데이터를 복제하려고 시도하는 것을 볼 수 있습니다.
기본 사이트에서 다음을 수행합니다.
- 오른쪽 상단 모서리에서 Admin을 선택합니다.
- 왼쪽 사이드바에서 Geo > Sites를 선택합니다.
- primary site를 확인하고 검증 정보를 살펴봅니다. 모든 업로드가 검증되었습니다.

- secondary site를 확인하고 검증 정보를 살펴봅니다. 보조 사이트가 같은 오브젝트 스토리지를 사용해야 하는데도 업로드 두 개가 여전히 동기화 중인 것을 볼 수 있습니다. 즉, 어떤 업로드도 동기화할 필요가 없어야 합니다.

불일치 정리#
삭제 명령을 실행하기 전에 최신 상태의 정상 백업이 있는지 확인합니다.
앞의 시나리오에서는 여러 업로드가 불일치를 일으키며, 아래에서 이를 예시로 사용합니다.
남은 잔여 항목을 올바르게 삭제하려면 다음과 같이 진행합니다.
-
확인된 불일치를 각각의 모델 이름에 매핑합니다. 모델 이름은 다음 단계에서 필요합니다.
오브젝트 스토리지 유형 모델 이름 백업 해당 없음 컨테이너 레지스트리 해당 없음 Mattermost 해당 없음 Autoscale 러너 캐싱 해당 없음 보안 파일 Ci::SecureFileJob 아티팩트 Ci::JobArtifact및Ci::PipelineArtifactLFS 오브젝트 LfsObject업로드 Upload머지 리퀘스트 diff MergeRequestDiff패키지 Packages::PackageFileDependency Proxy DependencyProxy::Blob및DependencyProxy::ManifestTerraform 상태 파일 Terraform::StateVersionPages 콘텐츠 PagesDeployment -
Rails 콘솔을 시작합니다.
-
이전 단계의 모델 이름을 기준으로, 오브젝트 스토리지가 아닌 로컬에 여전히 저장되어 있는 모든 "파일"을 조회합니다. 이 경우 업로드가 영향을 받으므로 모델 이름
Upload를 사용합니다.openbao.png가 여전히 로컬에 저장되어 있는 것을 확인합니다.Upload.with_files_stored_locally#] -
확인된 리소스의
id를 사용하여 올바르게 삭제합니다. 먼저find를 사용하여 올바른 리소스인지 확인한 다음destroy를 실행합니다.Upload.find(108) Upload.find(108).destroy -
선택 사항으로,
find를 다시 실행하여 리소스가 올바르게 삭제되었는지 확인합니다. 더 이상 찾을 수 없어야 합니다.Upload.find(108)ActiveRecord::RecordNotFound: Couldn't find Upload with 'id'=108
영향을 받는 모든 오브젝트 스토리지 유형에 대해 이 단계를 반복합니다.
다중 노드 GitLab 인스턴스에서 job 로그가 누락됨#
Rails 노드(웹 서비스 또는 Sidekiq를 실행하는 서버)가 두 개 이상인 GitLab 인스턴스에서는 러너가 job 로그를 전송한 뒤 모든 노드에서 로그를 사용할 수 있게 하는 메커니즘이 필요합니다. Job 로그는 로컬 디스크나 오브젝트 스토리지에 저장할 수 있습니다.
NFS를 사용하지 않고 증분 로깅 기능도 활성화하지 않은 경우 job 로그가 유실될 수 있습니다.
- 러너로부터 로그를 받은 노드가 로컬 디스크에 로그를 기록합니다.
- GitLab이 로그를 아카이브하려고 할 때, job이 로그에 접근할 수 없는 다른 서버에서 실행되는 경우가 많습니다.
- 오브젝트 스토리지에 대한 업로드가 실패합니다.
다음 오류가 /var/log/gitlab/gitlab-rails/exceptions_json.log에 함께 기록될 수도 있습니다.
{
"severity": "ERROR",
"exception.class": "Ci::AppendBuildTraceService::TraceRangeError",
"extra.build_id": 425187,
"extra.body_end": 12955,
"extra.stream_size": 720,
"extra.stream_class": {},
"extra.stream_range": "0-12954"
}
다중 노드 환경에서 CI 아티팩트를 오브젝트 스토리지에 기록하는 경우 증분 로깅 기능을 활성화해야 합니다.
Footnotes
-
use_iam_profile이true이면 GitLab Pages 배포의 기본값은900입니다. 기본적으로 GitLab Pages는 캐시된 사전 서명된 URL을 최대 11분 동안 제공할 수 있으며 (gitlab_cache_expiry와zip_cache_expiration의 합), 이 URL은 서명에 사용된 임시 자격 증명이 유효한 동안에만 유효합니다. EC2 인스턴스 프로필을 사용하면 이 기본값이 그 시간 범위를 줄이지만 없애지는 못합니다. 인스턴스 메타데이터 서비스가 AWS가 자격 증명을 교체할 때까지 같은 자격 증명을 반환하기 때문입니다. 통합 연결에 설정한 값은 GitLab Pages에도 적용되며 이 기본값을 대체합니다. ↩