对象存储
- Tier: 基础版, 专业版, 旗舰版
- Offering: 私有化部署
极狐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 文件和上传附件,可以通过为对象存储指定单一凭证与多个桶一起保存在对象存储中。
使用合并形式配置对象存储有许多优点:
- 可以简化您的极狐GitLab 配置,因为连接详细信息在对象类型之间共享。
- 允许使用加密的 S3 桶。
- 它使用适当的 Content-MD5 头将文件上传到 S3。
当使用合并形式时,直接上传会自动启用。因此,仅以下提供商可以使用:
- Amazon S3 兼容提供商
- Google Cloud Storage
- Azure Blob storage
合并形式配置不能用于备份或 Mattermost。备份可以单独配置服务器端加密。请参阅完整列表表格以获取支持的对象存储类型。
启用合并形式为所有对象类型启用对象存储。如果没有为所有桶指定,您可能会看到如下错误:
plaintextObject 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 | 安全文件 |
在每种对象类型中,可以定义三个参数:
有关示例,请参阅如何使用合并形式和 Amazon S3。
禁用特定功能的对象存储
如上所述,可以通过将 enabled 标志设置为 false 来禁用特定类型的对象存储。例如,要禁用 CI 产物的对象存储:
rubygitlab_rails['object_store']['objects']['artifacts']['enabled'] = false
如果功能完全禁用,则不需要桶。例如,如果使用此设置禁用 CI 产物,则不需要桶:
rubygitlab_rails['artifacts_enabled'] = false
为每种对象类型定义其自己的存储连接(存储特定形式)
使用存储特定形式,每个对象定义其自己的对象存储连接和配置。您应该使用合并形式,除非合并形式不支持的存储类型。当使用极狐GitLab Helm charts 时,请参考图表如何处理对象存储的合并形式。
使用加密的 S3 桶与非合并形式是不支持的。如果您使用它,可能会得到ETag 不匹配错误。
对于合并形式不支持的存储类型,请参考以下指南:
配置连接设置
合并和存储特定形式都必须配置连接。以下部分描述了可以在 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 桶的角色:
json1{ 2 "Version": "2012-10-17", 3 "Statement": [ 4 { 5 "Effect": "Allow", 6 "Action": [ 7 "s3:PutObject", 8 "s3:GetObject", 9 "s3:DeleteObject" 10 ], 11 "Resource": "arn:aws:s3:::test-bucket/*" 12 }, 13 { 14 "Effect": "Allow", 15 "Action": [ 16 "s3:ListBucket" 17 ], 18 "Resource": "arn:aws:s3:::test-bucket" 19 } 20 ] 21} -
将此角色附加到托管您的极狐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 中看到以下错误:
plaintextSTREAMING-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 |
-
编辑 /etc/gitlab/gitlab.rb 并添加以下行,替换为您想要的值:
ruby1gitlab_rails['object_store']['connection'] = { 2 'provider' => 'AzureRM', 3 'azure_storage_account_name' => '<AZURE STORAGE ACCOUNT NAME>', 4 'azure_storage_access_key' => '<AZURE STORAGE ACCESS KEY>', 5 'azure_storage_domain' => '<AZURE STORAGE DOMAIN>' 6} 7gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' 8gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' 9gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' 10gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' 11gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' 12gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' 13gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' 14gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' 15gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'如果您使用的是工作负载身份,请省略 azure_storage_access_key:
rubygitlab_rails['object_store']['connection'] = { 'provider' => 'AzureRM', 'azure_storage_account_name' => '<AZURE STORAGE ACCOUNT NAME>', 'azure_storage_domain' => '<AZURE STORAGE DOMAIN>' } -
保存文件并重新配置极狐GitLab:
shellsudo gitlab-ctl reconfigure
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)
Storj 网络提供一个 S3 兼容的 API 网关。使用以下配置示例:
ruby1gitlab_rails['object_store']['connection'] = { 2 'provider' => 'AWS', 3 'endpoint' => 'https://gateway.storjshare.io', 4 'path_style' => true, 5 'region' => 'eu1', 6 'aws_access_key_id' => 'ACCESS_KEY', 7 'aws_secret_access_key' => 'SECRET_KEY', 8 'aws_signature_version' => 2, 9 'enable_signature_v4_streaming' => false 10}
签名版本必须为 2。使用 v4 会导致 HTTP 411 Length Required 错误。
Hitachi Vantara HCP
HCP 提供一个 S3 兼容的 API。使用以下配置示例:
ruby1gitlab_rails['object_store']['connection'] = { 2 'provider' => 'AWS', 3 'endpoint' => 'https://<tenant_endpoint>', 4 'path_style' => true, 5 'region' => 'eu1', 6 'aws_access_key_id' => 'ACCESS_KEY', 7 'aws_secret_access_key' => 'SECRET_KEY', 8 'aws_signature_version' => 4, 9 'enable_signature_v4_streaming' => false 10} 11 12# <namespace_name/bucket_name> 格式示例 13gitlab_rails['object_store']['objects']['artifacts']['bucket'] = '<namespace_name>/<bucket_name>'
使用合并形式和 Amazon S3 的完整示例
以下示例使用 AWS S3 为所有支持的服务启用对象存储:
-
编辑 /etc/gitlab/gitlab.rb 并添加以下行,替换您想要的值:
ruby1# 合并对象存储配置 2gitlab_rails['object_store']['enabled'] = true 3gitlab_rails['object_store']['proxy_download'] = false 4gitlab_rails['object_store']['connection'] = { 5 'provider' => 'AWS', 6 'region' => 'eu-central-1', 7 'aws_access_key_id' => '<AWS_ACCESS_KEY_ID>', 8 'aws_secret_access_key' => '<AWS_SECRET_ACCESS_KEY>' 9} 10# 可选:仅在需要服务器端加密时需要以下行 11gitlab_rails['object_store']['storage_options'] = { 12 'server_side_encryption' => '<AES256 or aws:kms>', 13 'server_side_encryption_kms_key_id' => '<arn:aws:kms:xxx>' 14} 15gitlab_rails['object_store']['objects']['artifacts']['bucket'] = 'gitlab-artifacts' 16gitlab_rails['object_store']['objects']['external_diffs']['bucket'] = 'gitlab-mr-diffs' 17gitlab_rails['object_store']['objects']['lfs']['bucket'] = 'gitlab-lfs' 18gitlab_rails['object_store']['objects']['uploads']['bucket'] = 'gitlab-uploads' 19gitlab_rails['object_store']['objects']['packages']['bucket'] = 'gitlab-packages' 20gitlab_rails['object_store']['objects']['dependency_proxy']['bucket'] = 'gitlab-dependency-proxy' 21gitlab_rails['object_store']['objects']['terraform_state']['bucket'] = 'gitlab-terraform-state' 22gitlab_rails['object_store']['objects']['ci_secure_files']['bucket'] = 'gitlab-ci-secure-files' 23gitlab_rails['object_store']['objects']['pages']['bucket'] = 'gitlab-pages'如果您使用 AWS IAM profiles,请省略 AWS 访问密钥和秘密密钥/值对。例如:
rubygitlab_rails['object_store']['connection'] = { 'provider' => 'AWS', 'region' => 'eu-central-1', 'use_iam_profile' => true } -
保存文件并重新配置极狐GitLab:
shellsudo gitlab-ctl reconfigure
迁移到对象存储
要将现有的本地数据迁移到对象存储,请参阅以下指南:
过渡到合并形式
在特定存储配置中:
- 所有类型的对象(如 CI/CD 产物、LFS 文件和上传附件)的对象存储配置是独立配置的。
- 对象存储连接参数(如密码和端点 URL)为每种类型重复配置。
例如,Linux 软件包安装可能具有以下配置:
ruby1# 原始对象存储配置 2gitlab_rails['artifacts_object_store_enabled'] = true 3gitlab_rails['artifacts_object_store_direct_upload'] = true 4gitlab_rails['artifacts_object_store_proxy_download'] = false 5gitlab_rails['artifacts_object_store_remote_directory'] = 'artifacts' 6gitlab_rails['artifacts_object_store_connection'] = { 'provider' => 'AWS', 'aws_access_key_id' => 'access_key', 'aws_secret_access_key' => 'secret' } 7gitlab_rails['uploads_object_store_enabled'] = true 8gitlab_rails['uploads_object_store_direct_upload'] = true 9gitlab_rails['uploads_object_store_proxy_download'] = false 10gitlab_rails['uploads_object_store_remote_directory'] = 'uploads' 11gitlab_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:
shellrclone config配置过程是交互式的。至少添加两个 "remotes":一个用于当前存储数据的对象存储提供商(old),一个用于您正在转移到的提供商(new)。
-
验证您可以读取旧数据。以下示例指的是 uploads 存储桶,但您的存储桶可能有不同的名称:
shellrclone ls old:uploads | head这应该打印出当前存储在您的 uploads 存储桶中的对象的部分列表。如果您收到错误或列表为空,请返回并使用 rclone config 更新您的 Rclone 配置。
-
执行初始复制。您无需为此步骤使极狐GitLab服务器离线。
shellrclone 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 中出现错误:
plaintext411 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 会生成此错误:
plaintextLFS: lfsapi/client: refusing insecure redirect, https->http -
客户端需要信任对象存储证书颁发机构,否则可能返回常见的 TLS 错误,例如:
plaintextx509: certificate signed by unknown authority -
客户端需要网络访问对象存储。网络防火墙可能会阻止访问。如果未开启访问,可能会导致错误:
plaintextReceived status code 403 from server: Forbidden -
对象存储桶需要允许来自极狐GitLab实例 URL 的跨源资源共享 (CORS) 访问。尝试在存储库页面加载 PDF 时可能会显示以下错误:
plaintextAn 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管理员运行以下命令:
rubyFeature.disable(:s3_multithreaded_uploads)
通过 Rails 控制台进行手动测试
在某些情况下,使用 Rails 控制台测试对象存储设置可能会有所帮助。以下示例测试给定的一组连接设置,尝试写入测试对象,并最终读取它。
-
启动Rails 控制台。
-
设置对象存储连接,使用您在 /etc/gitlab/gitlab.rb 中设置的相同参数,格式如下:
使用现有上传配置的示例连接:
rubysettings = Gitlab.config.uploads.object_store.connection.deep_symbolize_keys connection = Fog::Storage.new(settings)使用访问密钥的示例连接:
ruby1connection = Fog::Storage.new( 2 { 3 provider: 'AWS', 4 region: 'eu-central-1', 5 aws_access_key_id: '<AWS_ACCESS_KEY_ID>', 6 aws_secret_access_key: '<AWS_SECRET_ACCESS_KEY>' 7 } 8)使用 AWS IAM Profiles 的示例连接:
ruby1connection = Fog::Storage.new( 2 { 3 provider: 'AWS', 4 use_iam_profile: true, 5 region: 'us-east-1' 6 } 7) -
指定要测试的存储桶名称,写入并最终读取测试文件。
rubydir = 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 环境变量:
rubyENV['EXCON_DEBUG'] = "1"
迁移到对象存储后的不一致
从本地迁移到对象存储时可能会发生数据不一致。特别是在与Geo结合时,当文件在迁移之前被手动删除时。
例如,实例管理员在本地文件系统上手动删除几个产物。这些更改未正确传播到数据库中,导致不一致。在迁移到对象存储后,这些不一致仍然存在并可能导致摩擦。Geo 副本可能会继续尝试复制这些文件,因为它们仍然在数据库中引用但不再存在。
使用 Geo 时识别不一致
假设以下 Geo 场景:
- 环境由一个 Geo 主节点和一个副节点组成
- 两个系统都已迁移到对象存储
- 副本使用与主节点相同的对象存储
- 选项 允许此副本站点复制对象存储上的内容 被禁用
- 在对象存储迁移之前,多个上传被手动删除
- 在此示例中,两个图像上传到一个议题
在这种情况下,副本不再需要复制任何数据,因为它使用与主节点相同的对象存储。由于不一致,管理员可以观察到副本仍然尝试复制数据:
在主站点上:
- 在左侧边栏底部,选择 管理员。
- 选择 Geo > 站点。
- 查看主站点并检查验证信息。注意所有上传都已验证:

- 查看副站点并检查验证信息。注意两个上传仍在同步,即使副本应该使用相同的对象存储。意味着它不应该需要同步任何上传:

清理不一致
基于之前的场景,多个上传导致的不一致在下面用作示例。
按照以下步骤正确删除潜在的剩余项:
-
将识别的不一致映射到它们各自的模型名称。模型名称在后续步骤中需要。
对象存储类型 模型名称 备份 不适用 容器注册表 不适用 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 仍然存储在本地:
rubyUpload.with_files_stored_locallyruby1#<Upload:0x00007d35b69def68 2 id: 108, 3 size: 13346, 4 path: "c95c1c9bf91a34f7d97346fd3fa6a7be/openbao.png", 5 checksum: "db29d233de49b25d2085dcd8610bac787070e721baa8dcedba528a292b6e816b", 6 model_id: 2, 7 model_type: "Project", 8 uploader: "FileUploader", 9 created_at: Wed, 02 Apr 2025 05:56:47.941319000 UTC +00:00, 10 store: 1, 11 mount_point: nil, 12 secret: "[FILTERED]", 13 version: 2, 14 uploaded_by_user_id: 1, 15 organization_id: nil, 16 namespace_id: nil, 17 project_id: 2, 18 verification_checksum: nil>] -
使用识别资源的 id 以正确删除它们。首先使用 find 验证它是正确的资源,然后运行 destroy:
rubyUpload.find(108) Upload.find(108).destroy -
可选,运行 find 再次验证资源已正确删除,应不再找到它:
rubyUpload.find(108)rubyActiveRecord::RecordNotFound: Couldn't find Upload with 'id'=108
对所有受影响的对象存储类型重复这些步骤。