- 支持的对象存储提供商
- 为所有对象类型配置单一存储连接(合并形式)
- 为每种对象类型定义其自己的存储连接(存储特定形式)
- 配置连接设置
- 使用合并形式和 Amazon S3 的完整示例
- 迁移到对象存储
- 过渡到合并形式
- 迁移对象到不同的对象存储提供商
- 文件系统存储的替代方案
-
故障排除
- 对象未包含在极狐GitLab备份中
- 使用独立存储桶
- S3 API 兼容性问题
- 产物始终以文件名
download
下载 - 代理下载
- ETag 不匹配
- 多线程复制
- 通过 Rails 控制台进行手动测试
- 迁移到对象存储后的不一致
{{< details >}}
- Tier: 基础版, 专业版, 旗舰版
- Offering: 私有化部署
{{< /details >}}
极狐GitLab 支持使用对象存储服务来存储多种类型的数据。相较于 NFS,建议使用对象存储,因为在大型设置中,对象存储通常具有更高的性能、可靠性和可扩展性。
要配置对象存储,您有两种选择:
- 推荐的。为所有对象类型配置单一存储连接:所有支持的对象类型共享一个凭证。这称为合并形式。
-
为每种对象类型定义其自己的存储连接:每个对象定义其自己的对象存储连接和配置。这称为存储特定形式。
如果您已经使用存储特定形式,请查看如何转换为合并形式。
如果您将数据存储在本地,请查看如何迁移到对象存储。
支持的对象存储提供商
具体来说,极狐GitLab 已经在多个对象存储提供商上经过了供应商和客户的测试:
- Amazon S3
- Google Cloud Storage
- Digital Ocean Spaces (兼容 S3)
- Oracle Cloud Infrastructure
- OpenStack Swift (兼容 S3 模式)
- Azure Blob storage
- MinIO (兼容 S3)
- 来自各种存储供应商的本地硬件和设备,其列表尚未正式建立。
为所有对象类型配置单一存储连接(合并形式)
大多数类型的对象,如 CI 产物、LFS 文件和上传附件,可以通过为对象存储指定单一凭证与多个桶一起保存在对象存储中。
{{< alert type=”note” >}}
对于极狐GitLab Helm Charts,请参阅如何配置合并形式。
{{< /alert >}}
使用合并形式配置对象存储有许多优点:
- 可以简化您的极狐GitLab 配置,因为连接详细信息在对象类型之间共享。
- 允许使用加密的 S3 桶。
- 它使用适当的
Content-MD5
头将文件上传到 S3。
当使用合并形式时,直接上传会自动启用。因此,仅以下提供商可以使用:
- Amazon S3 兼容提供商
- Google Cloud Storage
- Azure Blob storage
合并形式配置不能用于备份或 Mattermost。备份可以单独配置服务器端加密。请参阅完整列表表格以获取支持的对象存储类型。
启用合并形式为所有对象类型启用对象存储。如果没有为所有桶指定,您可能会看到如下错误:
Object storage for <object type> must have a bucket specified
如果您希望为特定对象类型使用本地存储,可以禁用特定功能的对象存储。
配置公共参数
在合并形式中,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 |
页面 |
ci_secure_files |
安全文件 |
在每种对象类型中,可以定义三个参数:
设置 | 必须? | 描述 |
---|---|---|
bucket |
{{< icon name=”check-circle” >}} 是* | 对象类型的桶名称。如果 enabled 设置为 false 则不需要。 |
enabled |
{{< icon name=”dotted-circle” >}} 否 | 覆盖公共参数。 |
proxy_download |
{{< icon name=”dotted-circle” >}} 否 | 覆盖公共参数。 |
有关示例,请参阅如何使用合并形式和 Amazon S3。
禁用特定功能的对象存储
如上所述,可以通过将 enabled
标志设置为 false
来禁用特定类型的对象存储。例如,要禁用 CI 产物的对象存储:
gitlab_rails['object_store']['objects']['artifacts']['enabled'] = false
如果功能完全禁用,则不需要桶。例如,如果使用此设置禁用 CI 产物,则不需要桶:
gitlab_rails['artifacts_enabled'] = false
为每种对象类型定义其自己的存储连接(存储特定形式)
使用存储特定形式,每个对象定义其自己的对象存储连接和配置。您应该使用合并形式,除非合并形式不支持的存储类型。当使用极狐GitLab Helm charts 时,请参考图表如何处理对象存储的合并形式。
使用加密的 S3 桶与非合并形式是不支持的。如果您使用它,可能会得到ETag 不匹配错误。
{{< alert type=”note” >}}
对于存储特定形式,直接上传可能成为默认,因为它不需要共享文件夹。
{{< /alert >}}
对于合并形式不支持的存储类型,请参考以下指南:
对象存储类型 | 是否支持合并形式? |
---|---|
备份 | {{< icon name=”dotted-circle” >}} 否 |
容器注册表 (可选功能) | {{< icon name=”dotted-circle” >}} 否 |
Mattermost | {{< icon name=”dotted-circle” >}} 否 |
自动缩放 runner 缓存 (可选以提高性能) | {{< icon name=”dotted-circle” >}} 否 |
安全文件 | {{< icon name=”check-circle” >}} 是 |
任务产物 包括归档的任务日志 | {{< icon name=”check-circle” >}} 是 |
LFS 对象 | {{< icon name=”check-circle” >}} 是 |
上传 | {{< icon name=”check-circle” >}} 是 |
合并请求差异 | {{< icon name=”check-circle” >}} 是 |
软件包 (可选功能) | {{< icon name=”check-circle” >}} 是 |
依赖代理 (可选功能) | {{< icon name=”check-circle” >}} 是 |
Terraform 状态文件 | {{< icon name=”check-circle” >}} 是 |
页面内容 | {{< icon name=”check-circle” >}} 是 |
配置连接设置
合并和存储特定形式都必须配置连接。以下部分描述了可以在 connection
设置中使用的参数。
Amazon S3
连接设置与 fog-aws 提供的设置相匹配:
设置 | 描述 | 默认值 |
---|---|---|
provider |
始终为兼容主机的 AWS 。 |
AWS |
aws_access_key_id |
AWS 凭证,或兼容。 | |
aws_secret_access_key |
AWS 凭证,或兼容。 | |
aws_signature_version |
使用的 AWS 签名版本。2 或 4 是有效选项。Digital Ocean 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 |
通过禁用访问检索 X-aws-ec2-metadata-token 的 IMDS v2 端点,强制使用 IMDS v1。 |
false |
使用 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" } ] }
- 将此角色附加到托管您的极狐GitLab 实例的 EC2 实例。
- 将
use_iam_profile
极狐GitLab 配置选项设置为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 资源名称。仅在 server_side_encryption 中使用 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 supported
Azure Blob 存储
虽然 Azure 使用 container
一词来表示一组 blob,极狐GitLab 统一使用 bucket
这个术语。请确保在 bucket
设置中配置 Azure 容器名称。
Azure Blob 存储只能与合并形式一起使用,因为使用一组凭据访问多个容器。存储特定形式不受支持。有关更多详细信息,请参见如何过渡到合并形式。
以下是 Azure 的有效连接参数。有关更多信息,请参见 Azure Blob Storage 文档。
设置 | 描述 | 示例 |
---|---|---|
provider |
提供商名称。 | AzureRM |
azure_storage_account_name |
用于访问存储的 Azure Blob Storage 帐户名称。 | azuretest |
azure_storage_access_key |
用于访问容器的存储帐户访问密钥。通常是一个以 base64 编码的 512 位加密密钥。对于 Azure 工作负载和托管标识 是可选的。 | czV2OHkvQj9FKEgrTWJRZVRoV21ZcTN0Nnc5eiRDJkYpSkBOY1JmVWpYbjJy\nNHU3eCFBJUQqRy1LYVBkU2dWaw==\n |
azure_storage_domain |
用于联系 Azure Blob Storage API 的域名(可选)。默认为 blob.core.windows.net 。如果您使用的是 Azure 中国、Azure 德国、Azure 美国政府或其他自定义 Azure 域,请设置此选项。 |
blob.core.windows.net |
{{< tabs >}}
{{< tab title=”Linux 软件包 (Omnibus)” >}}
-
编辑
/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
{{< /tab >}}
{{< tab title=”Helm chart (Kubernetes)” >}}
-
将以下内容放入一个名为
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 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
{{< /tab >}}
{{< tab title=”Docker” >}}
-
编辑
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 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
{{< /tab >}}
{{< tab title=”自编译 (source)” >}}
对于自编译的安装,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
{{< /tab >}}
{{< /tabs >}}
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 Data Contributor
角色。
Storj 网关 (SJ)
{{< alert type=”note” >}}
Storj 网关不支持多线程复制(请参阅表中的 UploadPartCopy
)。虽然计划实现,但在完成之前,您必须禁用多线程复制。
{{< /alert >}}
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 错误。
Hitachi Vantara HCP
{{< alert type=”note” >}}
连接到 HCP 可能会返回错误,提示 SignatureDoesNotMatch - 我们计算的请求签名与您提供的签名不匹配。请检查您的 HCP Secret Access 密钥和签名方法。
在这种情况下,将 endpoint
设置为租户的 URL 而不是命名空间,并确保 bucket 路径配置为 <namespace_name>/<bucket_name>
。
{{< /alert >}}
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 为所有支持的服务启用对象存储:
{{< tabs >}}
{{< tab title=”Linux package (Omnibus)” >}}
-
编辑
/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 or 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 profiles,请省略 AWS 访问密钥和秘密密钥/值对。例如:
gitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', 'region' => 'eu-central-1', 'use_iam_profile' => true }
-
保存文件并重新配置极狐GitLab:
sudo gitlab-ctl reconfigure
{{< /tab >}}
{{< tab title=”Helm chart (Kubernetes)” >}}
-
将以下内容放入名为
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 profiles,请省略 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
{{< /tab >}}
{{< tab title=”Docker” >}}
-
编辑
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 or 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 profiles,请省略 AWS 访问密钥和秘密密钥/值对。例如:
gitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', 'region' => 'eu-central-1', 'use_iam_profile' => true }
-
保存文件并重启极狐GitLab:
docker compose up -d
{{< /tab >}}
{{< tab title=”Self-compiled (source)” >}}
-
编辑
/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 profiles,请省略 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 profiles,请省略 AWS 访问密钥和秘密密钥/值对。例如:
[object_storage.s3] use_iam_profile = true
-
保存文件并重启极狐GitLab:
# 对于运行 systemd 的系统 sudo systemctl restart gitlab.target # 对于运行 SysV init 的系统 sudo service gitlab restart
{{< /tab >}}
{{< /tabs >}}
迁移到对象存储
要将现有的本地数据迁移到对象存储,请参阅以下指南:
过渡到合并形式
在特定存储配置中:
- 所有类型的对象(如 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
配置过程是交互式的。至少添加两个 “remotes”:一个用于当前存储数据的对象存储提供商(
old
),一个用于您正在转移到的提供商(new
)。 -
验证您可以读取旧数据。以下示例指的是
uploads
存储桶,但您的存储桶可能有不同的名称:rclone ls old:uploads | head
这应该打印出当前存储在您的
uploads
存储桶中的对象的部分列表。如果您收到错误或列表为空,请返回并使用rclone config
更新您的 Rclone 配置。 -
执行初始复制。您无需为此步骤使极狐GitLab服务器离线。
rclone sync -P old:uploads new:uploads
- 初次同步完成后,使用新对象存储提供商的 Web UI 或命令行界面验证新存储桶中是否有对象。如果没有,或者运行
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
-
对象存储桶需要允许来自极狐GitLab实例 URL 的跨源资源共享 (CORS) 访问。尝试在存储库页面加载 PDF 时可能会显示以下错误:
An error occurred while loading the file. Please try again later.
请参阅 LFS 文档了解更多详情。
此外,在短时间内,用户可以与他人共享预签名、限时对象存储 URL,而无需身份验证。此外,可能会在对象存储提供商和客户端之间产生带宽费用。
ETag 不匹配
使用默认极狐GitLab设置时,一些对象存储后端,如 MinIO 和 Alibaba 可能会生成 ETag mismatch
错误。
Amazon S3 加密
如果您在使用 Amazon Web Services S3 时看到此 ETag 不匹配错误,这可能是由于您的存储桶上的加密设置导致的。要解决此问题,您有两个选择:
对于 MinIO,推荐使用第一种选项。否则,MinIO 的解决方法是在服务器上使用 --compat
参数。
在没有启用合并形式或实例配置文件的情况下,极狐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。
多线程复制
极狐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 Profiles 的示例连接:
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 控制台中执行此操作,以避免在日志文件中泄露凭证。以下显示了如何为不同提供商启用请求调试:
{{< tabs >}}
{{< tab title=”Amazon S3” >}}
设置 EXCON_DEBUG
环境变量:
ENV['EXCON_DEBUG'] = "1"
{{< /tab >}}
{{< tab title=”Google Cloud Storage” >}}
配置记录器以记录到 STDOUT
:
Google::Apis.logger = Logger::new(STDOUT)
{{< /tab >}}
{{< tab title=”Azure Blob Storage” >}}
设置 DEBUG
环境变量:
ENV['DEBUG'] = "1"
{{< /tab >}}
{{< /tabs >}}
迁移到对象存储后的不一致
从本地迁移到对象存储时可能会发生数据不一致。特别是在与Geo结合时,当文件在迁移之前被手动删除时。
例如,实例管理员在本地文件系统上手动删除几个产物。这些更改未正确传播到数据库中,导致不一致。在迁移到对象存储后,这些不一致仍然存在并可能导致摩擦。Geo 副本可能会继续尝试复制这些文件,因为它们仍然在数据库中引用但不再存在。
使用 Geo 时识别不一致
假设以下 Geo 场景:
- 环境由一个 Geo 主节点和一个副节点组成
- 两个系统都已迁移到对象存储
- 副本使用与主节点相同的对象存储
- 选项
允许此副本站点复制对象存储上的内容
被禁用
- 在对象存储迁移之前,多个上传被手动删除
- 在此示例中,两个图像上传到一个议题
在这种情况下,副本不再需要复制任何数据,因为它使用与主节点相同的对象存储。由于不一致,管理员可以观察到副本仍然尝试复制数据:
在主站点上:
- 在左侧边栏底部,选择 管理员。
- 选择 Geo > 站点。
- 查看主站点并检查验证信息。注意所有上传都已验证:
- 查看副站点并检查验证信息。注意两个上传仍在同步,即使副本应该使用相同的对象存储。意味着它不应该需要同步任何上传:
清理不一致
{{< alert type=”warning” >}}
在发出任何删除命令之前,请确保您手头有最近且可用的备份。
{{< /alert >}}
基于之前的场景,多个上传导致的不一致在下面用作示例。
按照以下步骤正确删除潜在的剩余项:
-
将识别的不一致映射到它们各自的模型名称。模型名称在后续步骤中需要。
对象存储类型 模型名称 备份 不适用 容器注册表 不适用 Mattermost 不适用 自动缩放 runner 缓存 不适用 安全文件 Ci::SecureFile
作业产物 Ci::JobArtifact
和Ci::PipelineArtifact
LFS 对象 LfsObject
上传 Upload
合并请求差异 MergeRequestDiff
软件包 Packages::PackageFile
依赖代理 DependencyProxy::Blob
和DependencyProxy::Manifest
Terraform 状态文件 Terraform::StateVersion
Pages 内容 PagesDeployment
- 启动Rails 控制台。使用 Geo 时,在主站点上运行。
-
根据前一步的模型名称查询所有仍然存储在本地(而不是在对象存储中)的 “文件”。在这种情况下,由于上传受到影响,使用模型名称
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
对所有受影响的对象存储类型重复这些步骤。