Help us learn about your current experience with the documentation. Take the survey.

对象存储

  • 层级:Free、Premium、Ultimate
  • 提供:GitLab 自托管

GitLab 支持使用对象存储服务来存储多种类型的数据。 相较于NFS,它更受推荐;通常在较大的部署中表现更好,因为对象存储通常性能更高、更可靠且更具扩展性。

要配置对象存储,你有两个选择:

如果你的数据存储在本地,请查看如何迁移到对象存储

支持的对象存储提供商

GitLab 与 Fog 库紧密集成,因此你可以查看哪些提供商可与 GitLab 配合使用。

具体来说,GitLab 已由供应商和客户在各种对象存储提供商上进行了测试:

为所有对象类型配置单个存储连接(合并形式)

大多数类型的对象,如 CI 制品、LFS 文件和上传附件,可以通过指定包含多个桶的对象存储的单个凭证来保存到对象存储中。

对于 GitLab Helm Charts,请参阅如何配置合并形式

使用合并形式配置对象存储具有以下优势:

当使用合并形式时,直接上传会自动启用。因此,只能使用以下提供商:

合并形式的配置不能用于备份或 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 check-circle 是* 该对象类型的桶名称。若 enabled 设为 false 则无需此设置。
enabled dotted-circle 覆盖通用参数
proxy_download dotted-circle 覆盖通用参数

示例请参见如何使用统一表单和Amazon S3

禁用特定功能的对象存储

如前所述,可通过将 enabled 标志设为 false 来禁用特定类型的对象存储。例如,要禁用CI工件的存储:

gitlab_rails['object_store']['objects']['artifacts']['enabled'] = false

如果功能完全禁用,则不需要桶。例如,使用以下设置禁用CI工件时,无需桶:

gitlab_rails['artifacts_enabled'] = false

为每种对象类型配置各自的存储连接(存储特定表单)

通过存储特定表单,每个对象都会定义自身的对象存储连接与配置。除合并表单不支持的存储类型外,您应改用合并表单。使用 GitLab Helm 图表时,可参考图表对合并对象存储表单的处理方式。

非合并表单下不支持使用加密 S3 桶。若强制使用,可能会出现ETag 不匹配错误

对于存储特定表单,直接上传可能成为默认选项,因其无需共享文件夹。

针对合并表单不支持的存储类型,请参考以下指南:

对象存储类型 是否被合并表单支持?
备份数据 dotted-circle
容器注册表(可选功能) dotted-circle
Mattermost dotted-circle
自动扩容 Runner 缓存(提升性能的可选方案) dotted-circle
安全文件 check-circle
作业产物(含归档作业日志) check-circle
LFS 对象 check-circle
上传文件 check-circle
合并请求差异 check-circle
软件包(可选功能) check-circle
依赖代理(可选功能) check-circle
Terraform 状态文件 check-circle
Pages 内容 check-circle

配置连接设置

合并表单与存储特定表单均需配置连接。以下章节将介绍可用于 connection 设置的参数。

Amazon S3

连接设置与fog-aws提供的设置一致:

设置 描述 默认值
provider 兼容主机始终使用 AWS AWS
aws_access_key_id AWS凭证或兼容凭证。
aws_secret_access_key AWS凭证或兼容凭证。
aws_signature_version 要使用的AWS签名版本。有效选项为 24。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兼容主机,例如 localhoststorage.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都会获取临时凭证,因此配置中不需要硬编码的值。

先决条件:

设置实例配置文件的步骤:

  1. 创建具有必要权限的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"
            }
        ]
    }
  2. 附加此角色到托管你的GitLab实例的EC2实例上。

  3. 将GitLab配置选项 use_iam_profile 设为 true

加密的S3存储桶

无论是通过实例配置文件还是统一形式进行配置,GitLab Workhorse都能正确地将文件上传到已启用SSE-S3或SSE-KMS加密(默认)的S3存储桶中。AWS KMS密钥和SSE-C加密不受支持,因为这需要在每个请求中发送加密密钥

服务器端加密头

在S3存储桶上设置默认加密是最简单的启用加密方式,但你可能希望设置存储桶策略以确保仅上传已加密的对象。为此,你必须配置GitLab以在storage_options配置部分发送正确的加密头:

设置 描述
server_side_encryption 加密模式(AES256aws:kms)。
server_side_encryption_kms_key_id Amazon资源名称(ARN)。仅当server_side_encryption使用aws:kms时需要。参见AWS文档中关于使用KMS加密的内容

与默认加密的情况类似,这些选项仅在启用了Workhorse S3客户端时有效。必须满足以下两个条件之一:

  • 连接设置中use_iam_profiletrue
  • 使用合并表单。

如果未启用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

Google 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_locationgoogle_json_key_string

如果使用 ADC,请确保:

  • 您使用的服务账号具有 iam.serviceAccounts.signBlob 权限。通常的做法是为该服务账号授予 Service Account Token Creator 角色。

  • 如果您使用 Google Compute 虚拟机,请确保它们拥有访问 Google 云 API 的正确访问范围。如果机器没有正确的范围,错误日志可能会显示:

    Google::Apis::ClientError (insufficientPermissions: Request had insufficient authentication scopes.)

若要使用客户管理的加密密钥对存储桶进行加密,请使用 合并表单

  1. 编辑 /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
    }
  2. 保存文件并重新配置 GitLab:

    sudo gitlab-ctl reconfigure
  1. 将以下内容放入名为 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
  2. 创建 Kubernetes Secret:

    kubectl create secret generic -n <namespace> gitlab-object-storage --from-file=connection=object_storage.yaml
  3. 导出 Helm 值:

    helm get values gitlab > gitlab_values.yaml
  4. 编辑 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
  5. 保存文件并应用新值:

    helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
  1. 编辑 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
}
  1. 保存文件并重启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`  |

  1. 编辑 /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>'
    }
  2. 保存文件并重新配置 GitLab:

    sudo gitlab-ctl reconfigure
  1. 将以下内容放入名为 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
  2. 创建 Kubernetes Secret:

    kubectl create secret generic -n <namespace> gitlab-object-storage --from-file=connection=object_storage.yaml
  3. 导出 Helm 值:

    helm get values gitlab > gitlab_values.yaml
  4. 编辑 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
  1. 编辑 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>'
    }
  2. 保存文件并重启 GitLab:

    docker compose up -d

对于自编译安装,Workhorse 也需要配置 Azure 凭证。在 Linux 包安装中这并不需要,因为 Workhorse 的设置是从之前的设置中填充的。

  1. 编辑 /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
  2. 编辑 /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 调用中进行交换。

  3. 保存文件并重启 GitLab:

    # 对于运行 systemd 的系统
    sudo systemctl restart gitlab.target
    
    # 对于运行 SysV init 的系统
    sudo service gitlab restart

Azure 工作负载与托管身份

若要使用 Azure 工作负载身份托管身份,请在配置中省略 azure_storage_access_key。当 azure_storage_access_key 为空时,GitLab 会尝试执行以下操作:

  1. 通过 工作负载身份 获取临时凭据。环境中应包含 AZURE_TENANT_IDAZURE_CLIENT_IDAZURE_FEDERATED_TOKEN_FILE
  2. 若工作负载身份不可用,则向 Azure 实例元数据服务 请求凭据。
  3. 获取 用户委派密钥
  4. 使用该密钥生成 SAS 令牌以访问存储账户 blob。

请确保该身份已分配 Storage Blob 数据参与者 角色。

Storj Gateway (SJ)

Storj Gateway 不支持 多线程复制(参见表格中的 UploadPartCopy)。尽管有 实现计划,但在完成前必须 禁用多线程复制

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 为所有支持的服务启用对象存储:

  1. 编辑 /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
    }
  2. 保存文件并重新配置 GitLab:

    sudo gitlab-ctl reconfigure
  1. 将以下内容放入名为 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
  2. 创建 Kubernetes Secret:

    kubectl create secret generic -n <命名空间> gitlab-object-storage --from-file=connection=object_storage.yaml
  3. 导出 Helm 值:

    helm get values gitlab > gitlab_values.yaml
  4. 编辑 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
  5. 保存文件并应用新值:

    helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
  1. 编辑 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
}
  1. 保存文件并重启 GitLab:
docker compose up -d
  1. 编辑 /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
  1. 编辑 /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
  1. 保存文件并重启 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_enableduploads_object_store_connection)。

将对象迁移到不同的对象存储提供商

您可能需要将 GitLab 存储在对象存储中的数据迁移到其他对象存储提供商。以下步骤展示了如何使用 Rclone 完成此操作。

这些步骤假设您正在移动 uploads 桶,但相同流程适用于其他桶。

先决条件

  • 选择运行 Rclone 的计算机。根据迁移数据量,Rclone 可能需长时间运行,因此应避免使用会进入节能模式的笔记本或台式机。您可用 GitLab 服务器运行 Rclone。
  1. 安装 Rclone。

  2. 通过运行以下命令配置 Rclone:

    rclone config

    配置过程是交互式的。添加至少两个“远程”:一个用于当前存储数据的对象存储提供商(old),另一个用于目标提供商(new)。

  3. 验证可读取旧数据。以下示例引用 uploads 桶,但您的桶名可能不同:

    rclone ls old:uploads | head

    此命令应打印 uploads 桶中当前存储对象的局部列表。若报错或列表为空,请返回并用 rclone config 更新 Rclone 配置。

  4. 执行初始复制。此步骤无需将 GitLab 服务器离线。

    rclone sync -P old:uploads new:uploads
  5. 第一次同步完成后,用新对象存储提供商的 Web 界面或命令行接口,验证新桶中是否存在对象。若无对象或 rclone sync 报错,请检查 Rclone 配置后重试。

完成从旧位置到新位置的至少一次成功 Rclone 复制后,安排维护并关闭 GitLab 服务器。维护期间需执行两项操作:

  1. 执行最终 rclone sync 运行——因用户无法新增对象,故不会在旧桶遗留对象。
  2. 更新 GitLab 服务器的对象存储配置,使其对 uploads 使用新提供商。

文件系统存储的替代方案

如果您正在扩展 GitLab 实现,或添加容错性和冗余性,您可能需要移除对块设备或网络文件系统的依赖。请参阅以下额外指南:

  1. 确保 git 用户主目录 位于本地磁盘。
  2. 配置数据库查找 SSH 密钥,以消除对共享 authorized_keys 文件的需求。
  3. 防止作业日志使用本地磁盘
  4. 禁用 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_downloadfalse时,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设置时,部分对象存储后端(如MinIOAlibaba)可能生成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控制台测试对象存储设置可能很有帮助。以下示例测试一组给定的连接设置,尝试写入一个测试对象,并最终读取它。

  1. 启动Rails控制台

  2. 使用与/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'
      }
    )
  3. 指定要测试的目标存储桶名称,写入并最终读取一个测试文件。

    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):

  1. 编辑/etc/gitlab/gitlab.rb并添加以下行:

    gitlab_workhorse['env'] = {
      'AWS_DEBUG' => '1'
    }
  2. 保存文件并重新配置GitLab:

    sudo gitlab-ctl reconfigure

    S3兼容存储的请求和响应头会记录在/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主节点和一个次要节点
  • 两套系统均已完成对象存储迁移
    • 次要节点使用与主节点相同的对象存储
    • “允许此次要站点复制对象存储上的内容”选项处于关闭状态
  • 对象存储迁移前,有多个上传文件被手动删除
    • 本示例中,两张上传至问题的图片

在此场景下,次要节点因使用与主节点相同的对象存储,本无需再复制数据。但因存在不一致,管理员会发现次要节点仍在尝试复制数据:

在主节点上:

  1. 左侧边栏底部,选择管理员
  2. 选择Geo > 站点
  3. 查看主节点的验证信息,所有上传均已完成验证:
    显示主节点上传验证成功的Geo站点仪表板
  4. 查看次要节点的验证信息,注意到即便次要节点应使用相同对象存储,仍有两个上传正在进行同步——意味着其本不该再同步任何上传:
    显示次要节点不一致性的Geo站点仪表板

清理不一致性

确保在执行任何删除命令前,手头有最新且可用的备份。

基于之前的场景,多个 uploads 导致了不一致性,以下以此为例进行说明。

按以下步骤正确删除潜在残留项:

  1. 将识别到的不一致项映射到其对应的模型名称。后续步骤需要用到该模型名称。

    对象存储类型 模型名称
    备份(Backups) 不适用
    容器镜像仓库 不适用
    Mattermost 不适用
    自动扩容运行器缓存 不适用
    安全文件(Secure Files) Ci::SecureFile
    作业产物(Job artifacts) Ci::JobArtifactCi::PipelineArtifact
    LFS 对象 LfsObject
    上传文件(Uploads) Upload
    合并请求差异 MergeRequestDiff
    包(Packages) Packages::PackageFile
    依赖代理 DependencyProxy::BlobDependencyProxy::Manifest
    Terraform 状态文件 Terraform::StateVersion
    Pages 内容 PagesDeployment
  2. 启动一个 Rails 控制台

  3. 基于上一步的模型名称,查询所有仍存储在本地(而非对象存储)的“文件”。本例中受影响的是上传文件,因此使用模型名称 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>]
  4. 使用已识别资源的 id 正确删除它们。首先通过 find 验证是否为目标资源,然后执行 destroy

    Upload.find(108)
    Upload.find(108).destroy
  5. 可选操作:再次运行 find 验证资源是否已被正确删除(此时应无法再找到该资源):

    Upload.find(108)
    ActiveRecord::RecordNotFound: Couldn't find Upload with 'id'=108

对所有受影响的对象存储类型重复上述步骤。

多节点 GitLab 实例中作业日志缺失

在拥有多个 Rails 节点(运行 Web 服务或 Sidekiq 的服务器)的 GitLab 实例中,Runner 发送作业日志后,需有一种机制让所有节点都能访问这些日志。作业日志可存储在本地磁盘或对象存储中。

若未使用 NFS,且未启用 增量日志功能,则作业日志可能丢失:

  1. 接收 Runner 日志的节点将日志写入本地磁盘。
  2. 当 GitLab 尝试归档日志时,作业通常会在另一台无法访问该日志的服务器上运行。
  3. 上传至对象存储失败。

以下错误也可能被记录到 /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 产物写入对象存储,必须 启用增量日志功能