对象存储
- 层级:Free、Premium、Ultimate
- 提供:GitLab 自托管
GitLab 支持使用对象存储服务来存储多种类型的数据。 相较于NFS,它更受推荐;通常在较大的部署中表现更好,因为对象存储通常性能更高、更可靠且更具扩展性。
要配置对象存储,你有两个选择:
-
推荐。为所有对象类型配置单个存储连接:所有支持的的对象类型共享一个凭证。这称为合并形式。
-
为每个对象类型配置其自己的存储连接:每个对象定义自己的对象存储连接和配置。这称为特定存储形式。
如果你已使用特定存储形式,请查看如何过渡到合并形式。
如果你的数据存储在本地,请查看如何迁移到对象存储。
支持的对象存储提供商
GitLab 与 Fog 库紧密集成,因此你可以查看哪些提供商可与 GitLab 配合使用。
具体来说,GitLab 已由供应商和客户在各种对象存储提供商上进行了测试:
- Amazon S3(不支持[Object Lock](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lock.html),更多信息请参见问题 #335775)
- Google Cloud Storage
- Digital Ocean Spaces(与 S3 兼容)
- Oracle Cloud Infrastructure
- OpenStack Swift(S3 兼容模式)
- Azure Blob storage
- MinIO(与 S3 兼容)
- 各存储厂商的本地硬件和设备,该列表尚未正式确立。
为所有对象类型配置单个存储连接(合并形式)
大多数类型的对象,如 CI 制品、LFS 文件和上传附件,可以通过指定包含多个桶的对象存储的单个凭证来保存到对象存储中。
对于 GitLab Helm Charts,请参阅如何配置合并形式。
使用合并形式配置对象存储具有以下优势:
- 它可以简化你的 GitLab 配置,因为连接详情在对象类型之间共享。
- 它支持使用加密的 S3 桶。
- 它会以正确的
Content-MD5头上传文件到 S3。
当使用合并形式时,直接上传会自动启用。因此,只能使用以下提供商:
合并形式的配置不能用于备份或 Mattermost。备份可以单独通过服务器端加密进行配置。有关支持的对象存储类型的完整列表,请参见表格。
启用合并形式会为所有对象类型启用对象存储。如果未指定所有桶,你可能会看到如下错误:
对象存储 <对象类型> 必须指定一个桶如果你想对特定的对象类型使用本地存储,你可以禁用特定功能的对象存储。
在统一表单中,object_store 部分定义了一组通用参数。
| 设置 | 描述 |
|---|---|
enabled |
启用或禁用对象存储。 |
proxy_download |
设为 true 以启用所有文件的代理下载。该选项可减少出口流量,因为允许客户端直接从远程存储下载,而非代理所有数据。 |
connection |
下面描述的各种连接选项。 |
storage_options |
保存新对象时使用的选项,例如服务器端加密头。 |
objects |
每个对象的特定配置。 |
示例请参见如何使用统一表单和Amazon S3。
配置每个对象的参数
每个对象类型至少需定义其存储的桶名称。
下表列出了可用的有效 objects:
| 类型 | 描述 |
|---|---|
artifacts |
CI/CD作业工件 |
external_diffs |
合并请求差异 |
uploads |
用户上传 |
lfs |
Git大文件存储对象 |
packages |
项目包(例如PyPI、Maven或NuGet) |
dependency_proxy |
依赖代理 |
terraform_state |
Terraform状态文件 |
pages |
Pages |
ci_secure_files |
安全文件 |
在每个对象类型内,可以定义三个参数:
| 设置 | 是否必需? | 描述 |
|---|---|---|
bucket |
是* | 该对象类型的桶名称。若 enabled 设为 false 则无需此设置。 |
enabled |
否 | 覆盖通用参数。 |
proxy_download |
否 | 覆盖通用参数。 |
示例请参见如何使用统一表单和Amazon S3。
禁用特定功能的对象存储
如前所述,可通过将 enabled 标志设为 false 来禁用特定类型的对象存储。例如,要禁用CI工件的存储:
gitlab_rails['object_store']['objects']['artifacts']['enabled'] = false如果功能完全禁用,则不需要桶。例如,使用以下设置禁用CI工件时,无需桶:
gitlab_rails['artifacts_enabled'] = false为每种对象类型配置各自的存储连接(存储特定表单)
通过存储特定表单,每个对象都会定义自身的对象存储连接与配置。除合并表单不支持的存储类型外,您应改用合并表单。使用 GitLab Helm 图表时,可参考图表对合并对象存储表单的处理方式。
非合并表单下不支持使用加密 S3 桶。若强制使用,可能会出现ETag 不匹配错误。
对于存储特定表单,直接上传可能成为默认选项,因其无需共享文件夹。
针对合并表单不支持的存储类型,请参考以下指南:
| 对象存储类型 | 是否被合并表单支持? |
|---|---|
| 备份数据 | 否 |
| 容器注册表(可选功能) | 否 |
| Mattermost | 否 |
| 自动扩容 Runner 缓存(提升性能的可选方案) | 否 |
| 安全文件 | 是 |
| 作业产物(含归档作业日志) | 是 |
| LFS 对象 | 是 |
| 上传文件 | 是 |
| 合并请求差异 | 是 |
| 软件包(可选功能) | 是 |
| 依赖代理(可选功能) | 是 |
| Terraform 状态文件 | 是 |
| Pages 内容 | 是 |
配置连接设置
合并表单与存储特定表单均需配置连接。以下章节将介绍可用于 connection 设置的参数。
Amazon S3
连接设置与fog-aws提供的设置一致:
| 设置 | 描述 | 默认值 |
|---|---|---|
provider |
兼容主机始终使用 AWS。 |
AWS |
aws_access_key_id |
AWS凭证或兼容凭证。 | |
aws_secret_access_key |
AWS凭证或兼容凭证。 | |
aws_signature_version |
要使用的AWS签名版本。有效选项为 2 或 4。DigitalOcean Spaces等其他提供商可能需要 2。 |
4 |
enable_signature_v4_streaming |
设为 true 以启用带AWS v4签名的HTTP分块传输。Oracle Cloud S3需设为 false。GitLab 17.4将默认值从 true 改为 false。 |
false |
region |
AWS区域。 | |
host |
已弃用:请改用 endpoint。未使用AWS时的S3兼容主机,例如 localhost 或 storage.example.com。假设使用HTTPS和端口443。 |
s3.amazonaws.com |
endpoint |
配置S3兼容服务(如MinIO)时可使用,输入类似 http://127.0.0.1:9000 的URL。此参数优先于 host。始终使用 endpoint 以统一形式。 |
(可选) |
path_style |
设为 true 以使用 host/bucket_name/object 风格路径,而非 bucket_name.host/object。使用MinIO时设为 true。AWS S3则保持 false。 |
false |
use_iam_profile |
设为 true 以使用IAM配置文件代替访问密钥。 |
false |
aws_credentials_refresh_threshold_seconds |
使用IAM中的临时凭证时,设置自动刷新阈值(秒)。 | 15 |
disable_imds_v2 |
通过禁用访问IMDS v2端点(该端点检索 X-aws-ec2-metadata-token),强制使用IMDS v1。 |
false |
使用Amazon实例配置文件
无需在对象存储配置中提供AWS访问密钥和秘密密钥,你可以配置GitLab使用Amazon身份与访问管理(IAM)角色来设置一个Amazon实例配置文件。当使用此方法时,每次访问S3存储桶时,GitLab都会获取临时凭证,因此配置中不需要硬编码的值。
先决条件:
- 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" } ] } -
附加此角色到托管你的GitLab实例的EC2实例上。
-
将GitLab配置选项
use_iam_profile设为true。
加密的S3存储桶
无论是通过实例配置文件还是统一形式进行配置,GitLab Workhorse都能正确地将文件上传到已启用SSE-S3或SSE-KMS加密(默认)的S3存储桶中。AWS KMS密钥和SSE-C加密不受支持,因为这需要在每个请求中发送加密密钥。
服务器端加密头
在S3存储桶上设置默认加密是最简单的启用加密方式,但你可能希望设置存储桶策略以确保仅上传已加密的对象。为此,你必须配置GitLab以在storage_options配置部分发送正确的加密头:
| 设置 | 描述 |
|---|---|
server_side_encryption |
加密模式(AES256 或 aws:kms)。 |
server_side_encryption_kms_key_id |
Amazon资源名称(ARN)。仅当server_side_encryption使用aws:kms时需要。参见AWS文档中关于使用KMS加密的内容。 |
与默认加密的情况类似,这些选项仅在启用了Workhorse S3客户端时有效。必须满足以下两个条件之一:
- 连接设置中
use_iam_profile为true。 - 使用合并表单。
如果未启用Workhorse S3客户端而使用了服务器端加密头,则会发生ETag不匹配错误。
Oracle Cloud S3
Oracle Cloud S3必须确保使用以下设置:
| 设置 | 值 |
|---|---|
enable_signature_v4_streaming |
false |
path_style |
true |
如果enable_signature_v4_streaming设置为true,你可能会在production.log中看到以下错误:
STREAMING-AWS4-HMAC-SHA256-PAYLOAD is not supportedGoogle Cloud Storage (GCS)
以下是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 |
设为true以使用Google Cloud应用默认凭据来定位服务账号凭据。 |
GitLab会读取google_json_key_location的值,然后是google_json_key_string,最后是google_application_default。它使用这些设置中第一个有值的项。
服务账号必须有访问存储桶的权限。更多信息,请参阅云存储身份验证文档。
Google 云应用默认凭证
Google 云应用默认凭证(ADC) 通常与 GitLab 配合使用,以使用默认服务账号或 工作负载身份联合。
将 google_application_default 设为 true,并省略 google_json_key_location 和 google_json_key_string。
如果使用 ADC,请确保:
-
您使用的服务账号具有
iam.serviceAccounts.signBlob权限。通常的做法是为该服务账号授予Service Account Token Creator角色。 -
如果您使用 Google Compute 虚拟机,请确保它们拥有访问 Google 云 API 的正确访问范围。如果机器没有正确的范围,错误日志可能会显示:
Google::Apis::ClientError (insufficientPermissions: Request had insufficient authentication scopes.)
若要使用客户管理的加密密钥对存储桶进行加密,请使用 合并表单。
-
编辑
/etc/gitlab/gitlab.rb并添加以下行,替换为您想要的值:gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '<GOOGLE PROJECT>', 'google_json_key_location' => '<FILENAME>' }若要使用 ADC,请改用
google_application_default:gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '<GOOGLE PROJECT>', 'google_application_default' => true } -
保存文件并重新配置 GitLab:
sudo gitlab-ctl reconfigure
-
将以下内容放入名为
object_storage.yaml的文件中,用作 Kubernetes Secret:provider: Google google_project: <GOOGLE PROJECT> google_json_key_location: '<FILENAME>'若要使用 ADC,请改用
google_application_default:provider: Google google_project: <GOOGLE PROJECT> google_application_default: 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: | # 合并的对象存储配置 gitlab_rails['object_store']['enabled'] = true gitlab_rails['object_store']['proxy_download'] = false gitlab_rails['object_store']['connection'] = { 'provider' => 'Google', 'google_project' => '<GOOGLE PROJECT>', 'google_json_key_location' => '<FILENAME>' } 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`:
```ruby
gitlab_rails['object_store']['connection'] = {
'provider' => 'Google',
'google_project' => '<GOOGLE PROJECT>',
'google_application_default' => true
}- 保存文件并重启GitLab:
docker compose up -d
### Azure Blob 存储
尽管 Azure 使用单词 `container` 来表示 blob 的集合,但 GitLab 统一使用术语 `bucket`。请务必在 `bucket` 设置中配置 Azure 容器名称。
Azure Blob 存储只能与 [统一形式](#configure-a-single-storage-connection-for-all-object-types-consolidated-form) 配合使用,因为一组凭据用于访问多个容器。[特定于存储的形式](#configure-each-object-type-to-define-its-own-storage-connection-storage-specific-form) 不受支持。有关更多详情,请参阅 [如何过渡到统一形式](#transition-to-consolidated-form)。
以下是 Azure 的有效连接参数。更多信息请参见 [Azure Blob 存储文档](https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)。
| 设置 | 描述 | 示例 |
|-------------------------------|----------------------------------------------------------------------|--------------------------|
| `provider` | 提供商名称。 | `AzureRM` |
| `azure_storage_account_name` | 用于访问存储的 Azure Blob 存储账户名称。 | `azuretest` |
| `azure_storage_access_key` | 用于访问容器的存储账户访问密钥。这通常是秘密,以 base64 编码的 512 位加密密钥。对于 [Azure 工作负载和托管标识](#azure-workload-and-managed-identities),此字段可选。 | `czV2OHkvQj9FKEgrTWJRZVRoV21ZcTN0Nnc5eiRDJkYpSkBOY1JmVWpYbjJy\nNHU3eCFBJUQqRy1LYVBkU2dWaw==\n` |
| `azure_storage_domain` | 用于联系 Azure Blob 存储 API 的域名(可选)。默认值为 `blob.core.windows.net`。如果您使用 Azure 中国、Azure 德国、Azure 美国政府或其他自定义 Azure 域名,请设置此值。 | `blob.core.windows.net` |
-
编辑 /etc/gitlab/gitlab.rb 并添加以下行,替换为您想要的值:
gitlab_rails['object_store']['connection'] = {
'provider' => 'AzureRM',
'azure_storage_account_name' => '<AZURE STORAGE ACCOUNT NAME>',
'azure_storage_access_key' => '<AZURE STORAGE ACCESS KEY>',
'azure_storage_domain' => '<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'
如果您使用 工作负载标识,请省略 azure_storage_access_key:
gitlab_rails['object_store']['connection'] = {
'provider' => 'AzureRM',
'azure_storage_account_name' => '<AZURE STORAGE ACCOUNT NAME>',
'azure_storage_domain' => '<AZURE STORAGE DOMAIN>'
}
-
保存文件并重新配置 GitLab:
sudo gitlab-ctl reconfigure
-
将以下内容放入名为 object_storage.yaml 的文件中,用作 Kubernetes Secret:
provider: AzureRM
azure_storage_account_name: <YOUR_AZURE_STORAGE_ACCOUNT_NAME>
azure_storage_access_key: <YOUR_AZURE_STORAGE_ACCOUNT_KEY>
azure_storage_domain: blob.core.windows.net
如果您使用 工作负载或托管标识,请省略 azure_storage_access_key:
provider: AzureRM
azure_storage_account_name: <YOUR_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
### Helm Chart
1. 保存文件并应用新值:
```shell
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
-
编辑 docker-compose.yml:
version: "3.6"
services:
gitlab:
environment:
GITLAB_OMNIBUS_CONFIG: |
# 整合的对象存储配置
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 ACCOUNT NAME>',
'azure_storage_access_key' => '<AZURE STORAGE ACCESS KEY>',
'azure_storage_domain' => '<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'
如果您正在使用托管身份,请省略 azure_storage_access_key。
gitlab_rails['object_store']['connection'] = {
'provider' => 'AzureRM',
'azure_storage_account_name' => '<AZURE STORAGE ACCOUNT NAME>',
'azure_storage_domain' => '<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 ACCOUNT NAME>'
azure_storage_access_key: '<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 ACCOUNT NAME>"
azure_storage_access_key = "<AZURE STORAGE ACCESS KEY>"
如果您使用了自定义 Azure 存储域,azure_storage_domain 在 Workhorse 配置中不必设置。此信息会在 GitLab Rails 和 Workhorse 之间的 API 调用中进行交换。
-
保存文件并重启 GitLab:
# 对于运行 systemd 的系统
sudo systemctl restart gitlab.target
# 对于运行 SysV init 的系统
sudo service gitlab restart
Azure 工作负载与托管身份
若要使用 Azure 工作负载身份 或 托管身份,请在配置中省略 azure_storage_access_key。当 azure_storage_access_key 为空时,GitLab 会尝试执行以下操作:
- 通过 工作负载身份 获取临时凭据。环境中应包含
AZURE_TENANT_ID、AZURE_CLIENT_ID和AZURE_FEDERATED_TOKEN_FILE。 - 若工作负载身份不可用,则向 Azure 实例元数据服务 请求凭据。
- 获取 用户委派密钥。
- 使用该密钥生成 SAS 令牌以访问存储账户 blob。
请确保该身份已分配 Storage Blob 数据参与者 角色。
Storj Gateway (SJ)
Storj 网络 提供兼容 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
}
# 示例:<namespace_name/bucket_name> 格式
gitlab_rails['object_store']['objects']['artifacts']['bucket'] = '<namespace_name>/<bucket_name>'使用统一表单和 Amazon S3 的完整示例
以下示例使用 AWS S3 为所有支持的服务启用对象存储:
-
编辑
/etc/gitlab/gitlab.rb并添加以下行,替换为您需要的值:# 统一的对象存储配置 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_ACCESS_KEY_ID>', 'aws_secret_access_key' => '<AWS_SECRET_ACCESS_KEY>' } # 可选:如果需要服务器端加密,才需要以下行 gitlab_rails['object_store']['storage_options'] = { 'server_side_encryption' => '<AES256 或 aws:kms>', '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_ACCESS_KEY_ID> aws_secret_access_key: <AWS_SECRET_ACCESS_KEY>如果您使用 AWS IAM 配置文件,请省略 AWS 访问密钥和秘密访问密钥/值对。例如:
provider: AWS region: us-east-1 use_iam_profile: true -
创建 Kubernetes Secret:
kubectl create secret generic -n <命名空间> 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: | # 统一的对象存储配置 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_ACCESS_KEY_ID>', 'aws_secret_access_key' => '<AWS_SECRET_ACCESS_KEY>' } # 可选:如果需要服务器端加密,才需要以下行 gitlab_rails['object_store']['storage_options'] = { 'server_side_encryption' => '<AES256 或 aws:kms>', '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_ACCESS_KEY_ID>
aws_secret_access_key: <AWS_SECRET_ACCESS_KEY>
region: eu-central-1
storage_options:
server_side_encryption: <AES256 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-pages如果您使用AWS 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_ACCESS_KEY_ID>"
aws_secret_access_key = "<AWS_SECRET_ACCESS_KEY>"如果您使用AWS IAM 配置文件,请省略 AWS 访问密钥和秘密访问密钥/值对。例如:
[object_storage.s3]
use_iam_profile = true- 保存文件并重启 GitLab:
# 对于运行 systemd 的系统
sudo systemctl restart gitlab.target
# 对于运行 SysV init 的系统
sudo service gitlab restart迁移到对象存储
要将现有本地数据迁移到对象存储,请参阅以下指南:
过渡到合并形式
在存储特定的配置中:
- 所有类型的对象的存储配置(如 CI/CD 制品、LFS 文件和上传附件)均独立配置。
- 对象存储连接参数(如密码和端点 URL)针对每种类型重复设置。
例如,Linux 软件包安装可能有以下配置:
# 原始的对象存储配置
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配置过程是交互式的。添加至少两个“远程”:一个用于当前存储数据的对象存储提供商(
old),另一个用于目标提供商(new)。 -
验证可读取旧数据。以下示例引用
uploads桶,但您的桶名可能不同:rclone ls old:uploads | head此命令应打印
uploads桶中当前存储对象的局部列表。若报错或列表为空,请返回并用rclone config更新 Rclone 配置。 -
执行初始复制。此步骤无需将 GitLab 服务器离线。
rclone sync -P old:uploads new:uploads -
第一次同步完成后,用新对象存储提供商的 Web 界面或命令行接口,验证新桶中是否存在对象。若无对象或
rclone sync报错,请检查 Rclone 配置后重试。
完成从旧位置到新位置的至少一次成功 Rclone 复制后,安排维护并关闭 GitLab 服务器。维护期间需执行两项操作:
- 执行最终
rclone sync运行——因用户无法新增对象,故不会在旧桶遗留对象。 - 更新 GitLab 服务器的对象存储配置,使其对
uploads使用新提供商。
文件系统存储的替代方案
如果您正在扩展 GitLab 实现,或添加容错性和冗余性,您可能需要移除对块设备或网络文件系统的依赖。请参阅以下额外指南:
- 确保
git用户主目录 位于本地磁盘。 - 配置数据库查找 SSH 密钥,以消除对共享
authorized_keys文件的需求。 - 防止作业日志使用本地磁盘。
- 禁用 Pages 本地存储。
故障排除
对象未包含在 GitLab 备份中
如备份文档所述,对象未包含在 GitLab 备份中。您可以改用对象存储提供商启用备份。
使用单独的桶
为每种数据类型使用单独的桶是 GitLab 推荐的做法。这可确保 GitLab 存储的各种数据类型之间不会发生冲突。问题 292958 提议启用单桶的使用。
对于 Linux 软件包安装和自行编译安装,可以将单个实际桶拆分为多个虚拟桶。如果您的对象存储桶名为 my-gitlab-objects,则可以配置上传到 my-gitlab-objects/uploads、构件到 my-gitlab-objects/artifacts 等。应用程序的行为就好像这些都是单独的桶。使用桶前缀可能与 Helm 备份配合不佳。
基于 Helm 的安装需要单独的桶来处理备份恢复。
S3 API 兼容性问题
并非所有 S3 提供商都完全兼容 GitLab 使用的 Fog 库。症状包括 production.log 中出现错误:
411 Length Required工件始终以 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。
当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 -
对象存储桶需允许跨源资源共享(CORS)访问来自GitLab实例的URL。尝试在仓库页面加载PDF时,可能显示以下错误:
加载文件时出错。请稍后再试。更多详情见《LFS文档》。
此外,短期内用户可与他人共享预签名、限时的对象存储URL而无须认证。同时,对象存储提供商与客户端间可能产生带宽费用。
ETag不匹配
使用默认GitLab设置时,部分对象存储后端(如MinIO和Alibaba)可能生成ETag mismatch错误。
Amazon S3加密
若在Amazon Web Services S3中遇到此ETag不匹配错误,大概率是由于存储桶的加密设置所致。修复此问题有两种方案:
第一种方案推荐用于MinIO。否则,MinIO的解决方法是在服务器上使用--compat参数。
若未启用统一形式或实例配置文件,GitLab Workhorse会上传文件至S3,使用的预签名URL未计算Content-MD5 HTTP头。为确保数据未被篡改,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来加速存储桶内文件的复制。Ceph S3在Kraken 11.0.2之前的版本不支持此功能,并且在文件上传过程中复制时会返回404错误。
该功能可通过:s3_multithreaded_uploads特性标志禁用。若要禁用此功能,请让拥有Rails控制台访问权限的GitLab管理员运行以下命令:
Feature.disable(:s3_multithreaded_uploads)通过Rails控制台进行手动测试
在某些情况下,通过Rails控制台测试对象存储设置可能很有帮助。以下示例测试一组给定的连接设置,尝试写入一个测试对象,并最终读取它。
-
启动Rails控制台。
-
使用与
/etc/gitlab/gitlab.rb中相同的参数设置对象存储连接,示例如下:使用现有上传配置的连接示例:
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_ACCESS_KEY_ID>', aws_secret_access_key: '<AWS_SECRET_ACCESS_KEY>' } )使用AWS IAM Profile的连接示例:
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')
启用额外的调试信息
您还可以启用额外的调试以查看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中。
配置logger以输出到STDOUT:
Google::Apis.logger = Logger::new(STDOUT)设置DEBUG环境变量:
ENV['DEBUG'] = "1"重置Geo跟踪数据库以确保对象完全一致
假设以下Geo场景:
- 环境包含一个Geo主节点和一个次级节点。
- 您已在主节点上迁移至对象存储。
- 次级节点使用独立的对象存储桶。
- “允许此次级站点在对象存储上复制内容”选项已激活。
此类迁移可能导致对象在跟踪数据库中被标记为已同步,但在对象存储中实际缺失。在这种情况下,请重置您的Geo次级站点复制,以确保迁移后对象状态保持一致。
迁移到对象存储后出现的不一致
从本地迁移到对象存储时可能出现数据不一致。尤其是在结合Geo的情况下,若在迁移前手动删除过文件。
例如,实例管理员在本地文件系统上手动删除了几份工件(artifacts)。这类变更未正确同步至数据库,进而引发不一致。迁移到对象存储后,这些不一致仍会存在,还可能造成困扰。Geo次要节点可能持续尝试复制那些文件——因其在数据库中仍有引用,但实际已不存在。
用Geo识别不一致
假设如下Geo场景:
- 环境包含一个Geo主节点和一个次要节点
- 两套系统均已完成对象存储迁移
- 次要节点使用与主节点相同的对象存储
- “允许此次要站点复制对象存储上的内容”选项处于关闭状态
- 对象存储迁移前,有多个上传文件被手动删除
- 本示例中,两张上传至问题的图片
在此场景下,次要节点因使用与主节点相同的对象存储,本无需再复制数据。但因存在不一致,管理员会发现次要节点仍在尝试复制数据:
在主节点上:
- 左侧边栏底部,选择管理员。
- 选择Geo > 站点。
- 查看主节点的验证信息,所有上传均已完成验证:
- 查看次要节点的验证信息,注意到即便次要节点应使用相同对象存储,仍有两个上传正在进行同步——意味着其本不该再同步任何上传:
清理不一致性
确保在执行任何删除命令前,手头有最新且可用的备份。
基于之前的场景,多个 uploads 导致了不一致性,以下以此为例进行说明。
按以下步骤正确删除潜在残留项:
-
将识别到的不一致项映射到其对应的模型名称。后续步骤需要用到该模型名称。
对象存储类型 模型名称 备份(Backups) 不适用 容器镜像仓库 不适用 Mattermost 不适用 自动扩容运行器缓存 不适用 安全文件(Secure Files) Ci::SecureFile作业产物(Job artifacts) Ci::JobArtifact和Ci::PipelineArtifactLFS 对象 LfsObject上传文件(Uploads) Upload合并请求差异 MergeRequestDiff包(Packages) Packages::PackageFile依赖代理 DependencyProxy::Blob和DependencyProxy::ManifestTerraform 状态文件 Terraform::StateVersionPages 内容 PagesDeployment -
启动一个 Rails 控制台。
-
基于上一步的模型名称,查询所有仍存储在本地(而非对象存储)的“文件”。本例中受影响的是上传文件,因此使用模型名称
Upload。观察openbao.png仍存储在本地的示例:Upload.with_files_stored_locally#<Upload:0x00007d35b69def68 id: 108, size: 13346, path: "c95c1c9bf91a34f7d97346fd3fa6a7be/openbao.png", checksum: "db29d233de49b25d2085dcd8610bac787070e721baa8dcedba528a292b6e816b", model_id: 2, model_type: "Project", uploader: "FileUploader", created_at: Wed, 02 Apr 2025 05:56:47.941319000 UTC +00:00, store: 1, mount_point: nil, secret: "[FILTERED]", version: 2, uploaded_by_user_id: 1, organization_id: nil, namespace_id: nil, project_id: 2, verification_checksum: nil>] -
使用已识别资源的
id正确删除它们。首先通过find验证是否为目标资源,然后执行destroy:Upload.find(108) Upload.find(108).destroy -
可选操作:再次运行
find验证资源是否已被正确删除(此时应无法再找到该资源):Upload.find(108)ActiveRecord::RecordNotFound: Couldn't find Upload with 'id'=108
对所有受影响的对象存储类型重复上述步骤。
多节点 GitLab 实例中作业日志缺失
在拥有多个 Rails 节点(运行 Web 服务或 Sidekiq 的服务器)的 GitLab 实例中,Runner 发送作业日志后,需有一种机制让所有节点都能访问这些日志。作业日志可存储在本地磁盘或对象存储中。
若未使用 NFS,且未启用 增量日志功能,则作业日志可能丢失:
- 接收 Runner 日志的节点将日志写入本地磁盘。
- 当 GitLab 尝试归档日志时,作业通常会在另一台无法访问该日志的服务器上运行。
- 上传至对象存储失败。
以下错误也可能被记录到 /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 产物写入对象存储,必须 启用增量日志功能。