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

配置 Gitaly

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab Self-Managed

配置 Gitaly 有两种方式:

  1. 编辑 /etc/gitlab/gitlab.rb 并添加或修改 Gitaly 设置。参考 示例 Gitaly 配置文件。示例文件中的设置必须转换为 Ruby 格式。
  2. 保存文件并 重新配置 GitLab
  1. 编辑 /home/git/gitaly/config.toml 并添加或修改 Gitaly 设置。参考 示例 Gitaly 配置文件
  2. 保存文件并 重启 GitLab

以下配置选项也可用:

关于 Gitaly Token

整个 Gitaly 文档中提到的 Token 只是管理员选择的任意密码。它与为 GitLab API 或其他类似 Web API 创建的 Token 无关。

在独立服务器上运行 Gitaly

默认情况下,Gitaly 与 Gitaly 客户端在同一台服务器上运行,并按前文所述进行配置。单服务器安装最适合使用此默认配置,适用于:

但是,Gitaly 可以部署到其自己的服务器,这有利于跨多台机器的 GitLab 安装。

当配置为在独立服务器上运行时,Gitaly 服务器必须在集群中的 Gitaly 客户端之前进行 升级

磁盘需求 适用于 Gitaly 节点。

在独立服务器上设置 Gitaly 的流程如下:

  1. 安装 Gitaly
  2. 配置身份验证
  3. 配置 Gitaly 服务器
  4. 配置 Gitaly 客户端
  5. 在不必要的地方禁用 Gitaly(可选)。

网络架构

以下列表描述了 Gitaly 的网络架构:

  • GitLab Rails 将仓库分片到 repository storages 中。
  • /config/gitlab.yml 包含从存储名称到 (Gitaly 地址, Gitaly 令牌) 对的映射。
  • /config/gitlab.yml 中的存储名称 -> (Gitaly 地址, Gitaly 令牌) 映射是 Gitaly 网络拓扑的唯一真实来源。
  • (Gitaly 地址, Gitaly 令牌) 对应一个 Gitaly 服务器。
  • 一个 Gitaly 服务器托管一个或多个存储。
  • 一个 Gitaly 客户端可以使用一个或多个 Gitaly 服务器。
  • Gitaly 地址必须以所有 Gitaly 客户端都能正确解析的方式指定。
  • Gitaly 客户端包括:
    • Puma。
    • Sidekiq。
    • GitLab Workhorse。
    • GitLab Shell。
    • Elasticsearch indexer。
    • Gitaly 自身。
  • Gitaly 服务器必须能够使用其自身在 /config/gitlab.yml 中指定的 (Gitaly 地址, Gitaly 令牌) 对向自己发起 RPC 调用。
  • 身份验证通过静态令牌完成,该令牌在 Gitaly 和 GitLab Rails 节点之间共享。

下图展示了 Gitaly 服务器与 GitLab Rails 之间的通信,显示了 HTTP 和 HTTPS 通信的默认端口。

Two Gitaly servers and a GitLab Rails exchanging information.

Gitaly 服务器不得暴露于公共互联网,因为默认情况下 Gitaly 网络流量未加密。强烈建议使用防火墙限制对 Gitaly 服务器的访问。另一个选项是 使用 TLS

在以下章节中,我们将介绍如何配置两个带有密钥令牌 abc123secret 的 Gitaly 服务器:

  • gitaly1.internal
  • gitaly2.internal

我们假设您的 GitLab 安装有三个仓库存储:

  • default
  • storage1
  • storage2

如果需要,您可以使用最少一个服务器和一个仓库存储。

安装 Gitaly

在每个 Gitaly 服务器上安装 Gitaly,可通过以下方式之一:

  • Linux 包安装。下载并安装 您想要的 Linux 包,但不要提供 EXTERNAL_URL= 值。
  • 自行编译安装。按照 安装 Gitaly 中的步骤操作。

配置 Gitaly 服务器

要配置 Gitaly 服务器,您必须:

  • 配置身份验证。
  • 配置存储路径。
  • 启用网络监听器。

git 用户必须能够在配置的存储路径上读取、写入和设置权限。

为了避免轮换 Gitaly 令牌时出现停机时间,您可以暂时使用 gitaly['auth_transitioning'] 设置禁用身份验证。有关更多信息,请参阅 启用身份验证过渡模式

配置身份验证

Gitaly 和 GitLab 使用两个共享密钥进行身份验证:

  • Gitaly 令牌:用于向 Gitaly 进行 gRPC 请求的身份验证。
  • GitLab Shell 令牌:用于从 GitLab Shell 到 GitLab 内部 API 的身份验证回调。
  1. 要配置 Gitaly 令牌,请编辑 /etc/gitlab/gitlab.rb

    gitaly['configuration'] = {
       # ...
       auth: {
         # ...
         token: 'abc123secret',
       },
    }
  2. 通过以下两种方式之一配置 GitLab Shell 令牌

    • 方法 1(推荐):将 /etc/gitlab/gitlab-secrets.json 从 Gitaly 客户端复制到 Gitaly 服务器及其他 Gitaly 客户端的相同路径。

    • 方法 2:

      1. 在运行 GitLab Rails 的所有节点上,编辑 /etc/gitlab/gitlab.rb

      2. GITLAB_SHELL_SECRET_TOKEN 替换为真实密钥:

        • GitLab 17.5 及更高版本:

          gitaly['gitlab_secret'] = 'GITLAB_SHELL_SECRET_TOKEN'
        • GitLab 17.4 及更早版本:

          gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
      3. 在运行 Gitaly 的所有节点上,编辑 /etc/gitlab/gitlab.rb

      4. GITLAB_SHELL_SECRET_TOKEN 替换为真实密钥:

        • GitLab 17.5 及更高版本:

          gitaly['gitlab_secret'] = 'GITLAB_SHELL_SECRET_TOKEN'
        • GitLab 17.4 及更早版本:

          gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
      5. 完成上述更改后,重新配置 GitLab:

      sudo gitlab-ctl reconfigure
  1. /home/git/gitlab/.gitlab_shell_secret 从 Gitaly 客户端复制到 Gitaly 服务器(及其他 Gitaly 客户端)的相同路径。

  2. 在 Gitaly 客户端上,编辑 /home/git/gitlab/config/gitlab.yml

    gitlab:
      gitaly:
        token: 'abc123secret'
  3. 保存文件并重启 GitLab

  4. 在 Gitaly 服务器上,编辑 /home/git/gitaly/config.toml

    [auth]
    token = 'abc123secret'
  5. 保存文件并重启 GitLab

#### 配置Gitaly服务器

<!-- 更新示例需同步至以下位置:
- https://gitlab.com/gitlab-org/charts/gitlab/blob/master/doc/advanced/external-gitaly/external-omnibus-gitaly.md#configure-omnibus-gitlab
- https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/gitaly/index.md#gitaly-server-configuration
- 所有参考架构页面
-->

配置Gitaly服务器。

  1. 编辑 /etc/gitlab/gitlab.rb

    # 避免在Gitaly服务器上运行不必要的服务
    postgresql['enable'] = false
    redis['enable'] = false
    nginx['enable'] = false
    puma['enable'] = false
    sidekiq['enable'] = false
    gitlab_workhorse['enable'] = false
    gitlab_exporter['enable'] = false
    gitlab_kas['enable'] = false
    
    # 如果您运行独立的监控节点,可禁用这些服务
    prometheus['enable'] = false
    alertmanager['enable'] = false
    
    # 如果未运行独立监控节点,可启用Prometheus访问并禁用额外服务。
    # 这会使Prometheus监听所有接口。必须使用防火墙限制对该地址/端口的访问。
    # prometheus['listen_address'] = '0.0.0.0:9090'
    # prometheus['monitor_kubernetes'] = false
    
    # 如果不想运行监控服务,请取消以下注释(不推荐)
    # node_exporter['enable'] = false
    
    # 在'gitlab-ctl reconfigure'期间阻止数据库连接
    gitlab_rails['auto_migrate'] = false
    
    # 配置gitlab-shell API回调URL。缺少此配置会导致`git push`失败。
    # 此URL可以是您的"前端"GitLab URL或内部负载均衡器。
    # 别忘了将`/etc/gitlab/gitlab-secrets.json`从Gitaly客户端复制到Gitaly服务器。
    gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
    
    gitaly['configuration'] = {
       # ...
       #
       # 使Gitaly接受所有网络接口的连接。必须使用防火墙限制对该地址/端口的访问。
       # 如仅需支持TLS连接,请注释以下行
       listen_addr: '0.0.0.0:8075',
       auth: {
         # ...
         #
         # 认证令牌,确保只有授权服务器可与Gitaly服务器通信
         token: 'AUTH_TOKEN',
       },
    }
  2. 为每个Gitaly服务器向/etc/gitlab/gitlab.rb追加以下内容:

    gitaly1.internal 上:

    gitaly['configuration'] = {
       # ...
       storage: [
          {
             name: 'default',
             path: '/var/opt/gitlab/git-data/repositories',
          },
          {
             name: 'storage1',
             path: '/mnt/gitlab/git-data/repositories',
          },
       ],
    }

    gitaly2.internal 上:

    gitaly['configuration'] = {
       # ...
       storage: [
          {
             name: 'storage2',
             path: '/srv/gitlab/git-data/repositories',
          },
       ],
    }
  3. 保存文件并重新配置GitLab

  4. 确认Gitaly能对GitLab内部API执行回调:

    sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml
  1. 编辑 /home/git/gitaly/config.toml

    listen_addr = '0.0.0.0:8075'
    
    runtime_dir = '/var/opt/gitlab/gitaly'
    
    [logging]
    format = 'json'
    level = 'info'
    dir = '/var/log/gitaly'
  2. 为每个Gitaly服务器向/home/git/gitaly/config.toml追加以下内容:

    gitaly1.internal 上:

    [[storage]]
    name = 'default'
    path = '/var/opt/gitlab/git-data/repositories'
    
    [[storage]]
    name = 'storage1'
    path = '/mnt/gitlab/git-data/repositories'

    gitaly2.internal 上:

    [[storage]]
    name = 'storage2'
    path = '/srv/gitlab/git-data/repositories'
  3. 编辑 /home/git/gitlab-shell/config.yml

    gitlab_url: https://gitlab.example.com
  4. 保存文件并重启GitLab

  5. 确认Gitaly能对GitLab内部API执行回调:

    sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml

如果直接从GitLab服务器复制仓库数据到Gitaly,务必确保元数据文件(默认路径:/var/opt/gitlab/git-data/repositories/.gitaly-metadata)未被包含在传输中。复制该文件会导致GitLab尝试直接访问Gitaly服务器上的仓库,


导致 `Error creating pipeline` 和 `Commit not found` 错误,或过时数据。
### 配置 Gitaly 客户端 作为最后一步,您必须更新 Gitaly 客户端,从使用本地 Gitaly 服务切换到使用刚刚配置好的 Gitaly 服务器。

GitLab 要求配置一个 default 仓库存储。 了解此限制的更多信息

这可能会带来风险,因为任何阻止您的 Gitaly 客户端访问 Gitaly 服务器的情况都会导致所有 Gitaly 请求失败。例如,任何类型的网络、防火墙或名称解析问题。 Gitaly 做出以下假设: - 您的 `gitaly1.internal` Gitaly 服务器可以从 Gitaly 客户端通过 `gitaly1.internal:8075` 访问,且该 Gitaly 服务器可以对 `/var/opt/gitlab/git-data``/mnt/gitlab/git-data` 进行读写及设置权限操作。 - 您的 `gitaly2.internal` Gitaly 服务器可以从 Gitaly 客户端通过 `gitaly2.internal:8075` 访问,且该 Gitaly 服务器可以对 `/srv/gitlab/git-data` 进行读写及设置权限操作。 - 您的 `gitaly1.internal``gitaly2.internal` Gitaly 服务器可以相互访问。 除非使用 [混合配置](#mixed-configuration),否则不能将某些 Gitaly 服务器定义为本地 Gitaly 服务器(无 `gitaly_address`),而其他定义为远程服务器(有 `gitaly_address`)。 可通过以下两种方式之一配置 Gitaly 客户端。这些说明适用于未加密连接,但您也可以启用 [TLS 支持](tls_support.md):
  1. 编辑 /etc/gitlab/gitlab.rb

    # 使用在所有 Gitaly 服务器上配置的相同令牌值
    gitlab_rails['gitaly_token'] = '<AUTH_TOKEN>'
    
    gitlab_rails['repositories_storages'] = {
      'default'  => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
      'storage1' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
      'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
    }

    或者,如果每个 Gitaly 服务器配置了不同的认证令牌:

    gitlab_rails['repositories_storages'] = {
      'default'  => { 'gitaly_address' => 'tcp://gitaly1.internal:8075', 'gitaly_token' => '<AUTH_TOKEN_1>' },
      'storage1' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075', 'gitaly_token' => '<AUTH_TOKEN_1>' },
      'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075', 'gitaly_token' => '<AUTH_TOKEN_2>' },
    }
  2. 保存文件并 重新配置 GitLab

  3. 在 Gitaly 客户端(例如 Rails 应用程序)上运行 sudo gitlab-rake gitlab:gitaly:check 以确认其能连接到 Gitaly 服务器。

  4. 查看日志以观察请求:

    sudo gitlab-ctl tail gitaly
  1. 编辑 /home/git/gitlab/config/gitlab.yml

    gitlab:
      repositories:
        storages:
          default:
            gitaly_address: tcp://gitaly1.internal:8075
            gitaly_token: AUTH_TOKEN_1
          storage1:
            gitaly_address: tcp://gitaly1.internal:8075
            gitaly_token: AUTH_TOKEN_1
          storage2:
            gitaly_address: tcp://gitaly2.internal:8075
            gitaly_token: AUTH_TOKEN_2
  2. 保存文件并 重启 GitLab

  3. 运行 sudo -u git -H bundle exec rake gitlab:gitaly:check RAILS_ENV=production 以确认 Gitaly 客户端能连接到 Gitaly 服务器。

  4. 查看日志以观察请求:

    tail -f /home/git/gitlab/log/gitaly.log
当您在 Gitaly 服务器上查看 Gitaly 日志时,应能看到传入的请求。触发 Gitaly 请求的一个可靠方法是:通过 HTTP 或 HTTPS 从 GitLab 克隆仓库。

如果您配置了 服务器钩子(无论是针对单个仓库还是全局配置),则必须将其移至 Gitaly 服务器。如果有多个 Gitaly 服务器,请将服务器钩子复制到所有 Gitaly 服务器。

#### 混合配置 GitLab 可以与多个 Gitaly 服务器之一位于同一台服务器上,但不支持混合本地和远程配置的方式。以下配置是不正确的,因为: - 所有地址必须能被其他 Gitaly 服务器访问。 - `storage1``gitaly_address` 分配了一个 Unix 套接字,这对某些 Gitaly 服务器无效。 ```ruby gitlab_rails['repositories_storages'] = { 'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' }, 'storage1' => { 'gitaly_address' => 'unix:/var/opt/gitlab/gitaly/gitaly.socket' }, 'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' }, }

若要组合本地和远程 Gitaly 服务器,请为本地 Gitaly 服务器使用外部地址。例如:

gitlab_rails['repositories_storages'] = {
  'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
  # 运行 Gitaly 的 GitLab 服务器的地址
  'storage1' => { 'gitaly_address' => 'tcp://gitlab.internal:8075' },
  'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
}

gitaly['configuration'] = {
  # ...
  #
  # 让 Gitaly 接受所有网络接口的连接
  listen_addr: '0.0.0.0:8075',
  # 或启用 TLS
  tls_listen_addr: '0.0.0.0:9999',
  tls: {
    certificate_path:  '/etc/gitlab/ssl/cert.pem',
    key_path: '/etc/gitlab/ssl/key.pem',
  },
  storage: [
    {
      name: 'storage1',
      path: '/mnt/gitlab/git-data/repositories',
    },
  ],
}

path 仅能包含在本地 Gitaly 服务器上的存储分片。如果省略,将为该存储分片使用默认 Git 存储目录。

GitLab 需要默认仓库存储

向环境中添加 Gitaly 服务器时,你可能想替换原始的 default Gitaly 服务。但你不能重新配置 GitLab 应用程序服务器以移除 default 存储,因为 GitLab 需要名为 default 的存储。了解更多 关于此限制的信息。

要解决此限制:

  1. 在新的 Gitaly 服务上定义额外的存储位置,并将额外存储配置为 default。该存储位置必须有正在运行且可用的 Gitaly 服务,以避免数据库迁移出现问题(数据库迁移期望工作存储正常)。
  2. 管理区,将 default 权重设为零,防止在此处存储仓库。

(可选)在不必要时禁用 Gitaly

如果你将 Gitaly 作为远程服务运行,可以考虑禁用在 GitLab 服务器上默认运行的本地 Gitaly 服务,仅在需要的地方运行它。

仅当你在自定义集群配置中运行 GitLab 时,才应在 GitLab 实例上禁用 Gitaly——此时 Gitaly 运行在与 GitLab 实例分离的机器上。在集群的所有机器上禁用 Gitaly 不是有效配置(有些机器必须充当 Gitaly 服务器)。

可通过以下两种方式之一在 GitLab 服务器上禁用 Gitaly:

  1. 编辑 /etc/gitlab/gitlab.rb

    gitaly['enable'] = false
  2. 保存文件并重新配置 GitLab

  1. 编辑 /etc/default/gitlab

    gitaly_enabled=false
  2. 保存文件并重启 GitLab

更改 Gitaly 监听接口

你可以更改 Gitaly 监听的接口。当你有必须与 Gitaly 通信的外部服务时,可能需要更改监听接口。例如,当启用精确代码搜索但实际服务运行在其他服务器上时,使用 Zoekt 的精确代码搜索

gitaly_token 必须是一个秘密字符串,因为 gitaly_token 用于 Gitaly 服务的身份验证。可以使用 openssl rand -base64 24 生成随机 32 字符串来生成此密钥。

例如,要将 Gitaly 监听接口改为 0.0.0.0:8075

# /etc/gitlab/gitlab.rb

# 添加用于 Gitaly 身份验证的共享令牌
gitlab_shell['secret_token'] = 'your_secure_token_here'
gitlab_rails['gitaly_token'] = 'your_secure_token_here'

# Gitaly 配置
gitaly['gitlab_secret'] = 'your_secure_token_here'
gitaly['configuration'] = {
  listen_addr: '0.0.0.0:8075',
  auth: {
    token: 'your_secure_token_here',
  },
  storage: [
    {
      name: 'default',
      path: '/var/opt/gitlab/git-data/repositories',
    },
  ]
}

# 告诉 Rails 去何处查找 Gitaly
gitlab_rails['repositories_storages'] = {
  'default' => { 'gitaly_address' => 'tcp://ip_address_here:8075' },
}

内部API URL(多服务器设置重要)

gitlab_rails['internal_api_url'] = 'http://ip_address_here'

控制组

有关控制组的信息,请参阅 Cgroups

后台仓库优化

仓库中可能会积累空目录和不必要的配置项,拖慢Git操作速度。Gitaly可调度每日后台任务,设定最大执行时长来清理这些项目并提升性能。

后台仓库优化是一项实验性功能,运行时可能对主机造成显著负载。
请务必安排在非高峰时段执行,且持续时间较短(例如30 - 60分钟)。

可通过以下两种方式之一配置后台仓库优化:

编辑 /etc/gitlab/gitlab.rb 并添加:

gitaly['configuration'] = {
  # ...
  daily_maintenance: {
    # ...
    start_hour: 4,
    start_minute: 30,
    duration: '30m',
    storages: ['default'],
  },
}

编辑 /home/git/gitaly/config.toml 并添加:

[daily_maintenance]
start_hour = 4
start_minute = 30
duration = '30m'
storages = ["default"]

旋转 Gitaly 认证令牌

在生产环境中轮换凭证通常需要停机时间或导致服务中断。

不过,你可以在不停机的情况下轮换 Gitaly 凭证。轮换 Gitaly 认证令牌涉及以下步骤:

若你在单服务器上运行 GitLab,此流程同样适用。此时,Gitaly 服务端与客户端指向同一机器。

验证身份验证监控

轮换 Gitaly 认证令牌前,需验证能否通过 Prometheus 监控 GitLab 安装的身份验证行为

确认后即可继续后续步骤。

启用身份验证过渡模式

临时在 Gitaly 服务端禁用身份验证,将其置于身份验证过渡模式,操作如下:

# 在 /etc/gitlab/gitlab.rb 中
gitaly['configuration'] = {
  # ...
  auth: {
    # ...
    transitioning: true,
  },
}

修改后,你的 Prometheus 查询 应返回类似结果:

{enforced="false",status="would be ok"}  4424.985419441742

由于 enforced="false",安全启动新令牌的部署。

更新 Gitaly 认证令牌

要在每个 Gitaly 客户端和服务端更新为新令牌,操作如下:

  1. 更新配置:

    # 在 /etc/gitlab/gitlab.rb 中
    gitaly['configuration'] = {
       # ...
       auth: {
          # ...
          token: '<new secret token>',
       },
    }
  2. 重启 Gitaly:

    gitlab-ctl restart gitaly

若在部署过程中执行 Prometheus 查询,你会看到 enforced="false",status="denied" 计数器非零值。

确保无身份验证失败

新令牌设置完成后,重启所有相关服务,你会 暂时看到 以下混合状态:

  • status="would be ok"
  • status="denied"

当所有 Gitaly 客户端和服务端获取到新令牌后,唯一非零速率应为 enforced="false",status="would be ok"

禁用身份验证过渡模式

要重新启用 Gitaly 身份验证,需禁用身份验证过渡模式。在 Gitaly 服务端按以下方式更新配置:

# 在 /etc/gitlab/gitlab.rb 中
gitaly['configuration'] = {
  # ...
  auth: {
    # ...
    transitioning: false,
  },
}

未完成此步骤则无 Gitaly 身份验证。

验证身份验证已强制执行

刷新你的 Prometheus 查询。你现在应看到类似初始结果,例如:

{enforced="true",status="ok"}  4424.985419441742

enforced="true" 表示身份验证正在强制执行。

pack-objects 缓存

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

Gitaly,提供 Git 仓库存储的服务,可配置为缓存短时间的 Git fetch 响应。这能减少服务器在接收大量 CI fetch 流量时的负载。

pack-objects 缓存封装了 git pack-objects,这是 Git 的内部组件,通过使用 PostUploadPack 和 SSHUploadPack Gitaly RPCs 间接调用。当用户通过 HTTP 执行 Git fetch 时,Gitaly 运行 PostUploadPack;通过 SSH 执行时运行 SSHUploadPack。 启用缓存后,任何使用 PostUploadPack 或 SSHUploadPack 的操作都能受益。它独立于且不受以下因素影响:

  • 传输方式(HTTP 或 SSH)。
  • Git 协议版本(v0 或 v2)。
  • fetch 类型,例如完整克隆、增量 fetch、浅克隆或部分克隆。

该缓存的强项在于去重并发相同的 fetch 操作。它能:

  • 让用户运行大量并发作业的 CI/CD 管道的 GitLab 实例受益。服务器 CPU 利用率应有明显下降。
  • 对唯一 fetch 操作完全无益。例如,若你通过克隆仓库到本地电脑进行抽查,很可能看不到此缓存的好处,因为你的 fetch 可能是唯一的。

pack-objects 缓存是本地缓存。它:

  • 将元数据存储在启用了它的 Gitaly 进程的内存中。
  • 将正在缓存的 Git 数据存储在本地存储的文件中。

使用本地文件的优势在于,操作系统可能会自动将 pack-objects 缓存文件的部分内容保留在 RAM 中,使其更快。

由于 pack-objects 缓存可能导致磁盘写入 I/O 显著增加,因此默认关闭。

配置缓存

以下是 pack-objects 缓存的配置选项。每个选项将在下文详细讨论。

设置 默认值 描述
enabled false 开启缓存。关闭时,Gitaly 为每个请求运行专用的 git pack-objects 进程。
dir <第一个存储路径>/+gitaly/PackObjectsCache 缓存文件存储的本地目录。
max_age 5m(5 分钟) 超过此时间的缓存条目会被驱逐并从磁盘移除。
min_occurrences 1 创建缓存条目前,键必须出现的最小次数。

/etc/gitlab/gitlab.rb 中设置:

gitaly['configuration'] = {
  # ...
  pack_objects_cache: {
    enabled: true,
    # "dir"、"max_age" 和 "min_occurences" 的默认设置应该没问题。
    # 若要自定义这些,请参见下方详情。
  },
}

enabled 默认为 false

缓存默认禁用,因为在某些情况下,它可能导致 磁盘写入字节数极端增加。在 GitLab.com 上,我们已验证仓库存储磁盘能处理额外负载,但我们认为不能假设所有地方都如此。

缓存存储目录 dir

缓存需要一个目录来存储其文件。该目录应满足:

  • 位于有足够空间的文件系统中。如果缓存文件系统耗尽空间,所有获取操作都会失败。
  • 位于有足够IO带宽的磁盘上。如果缓存磁盘耗尽IO带宽,所有获取操作,可能还包括整个服务器,都会变慢。

指定目录中的所有现有数据都将被移除。请注意不要使用包含现有数据的目录。

默认情况下,缓存存储目录设置为配置文件中定义的第一个Gitaly存储的子目录。

多个Gitaly进程可以使用相同的目录作为缓存存储。每个Gitaly进程使用唯一的随机字符串作为其创建的缓存文件名的一部分。这意味着:

  • 它们不会发生冲突。
  • 它们不会复用其他进程的文件。

虽然默认目录将缓存文件放在与仓库数据相同的文件系统中,但这并非强制要求。如果你的基础设施更适合,可以将缓存文件放在不同的文件系统上。

所需磁盘IO带宽取决于:

  • Gitaly服务器上仓库的大小和结构。
  • 用户生成的流量类型。

你可以使用 gitaly_pack_objects_generated_bytes_total 指标作为悲观估计,假设你的缓存命中率是0%。

所需空间取决于:

  • 用户从缓存中拉取的字节每秒。
  • max_age 缓存驱逐窗口的大小。

如果你的用户以100 MB/s的速度拉取,并且你使用了5分钟的窗口,那么平均而言,你的缓存目录中有 5*60*100 MB = 30 GB 的数据。这个平均值是预期平均值,而非保证值。峰值大小可能会超过此平均值。

缓存驱逐窗口 max_age

max_age 配置设置让你能够控制缓存命中的概率以及缓存文件的平均存储用量。比 max_age 旧的条目会被从磁盘中删除。

驱逐操作不会干扰正在进行的请求。即使 max_age 小于通过慢速连接执行获取操作的时间也没关系,因为Unix文件系统只有在读取已删除文件的所有进程都关闭后才会真正删除该文件。

最小键出现次数 min_occurrences

min_occurrences 设置控制在对相同请求创建新的缓存条目前,该请求必须出现的次数。默认值为 1,表示唯一请求不会被写入缓存。

如果你:

  • 增加这个数字,你的缓存命中率会下降,而缓存占用的磁盘空间会减少。
  • 减少这个数字,你的缓存命中率会上升,而缓存占用的磁盘空间会增加。

你应该将 min_occurrences 设为 1。在GitLab.com上,从0改为1为我们节省了50%的缓存磁盘空间,同时对缓存命中率的影响微乎其微。

观察缓存

你可以通过 指标 和以下记录的信息来观察该缓存。这些日志属于 gRPC 日志的一部分,可以在执行调用时发现。

字段 描述
pack_objects_cache.hit 表示当前 pack-objects 缓存是否被命中(truefalse
pack_objects_cache.key 用于 pack-objects 缓存的缓存键
pack_objects_cache.generated_bytes 正在被写入的新缓存的大小(以字节为单位)
pack_objects_cache.served_bytes 被服务的缓存大小(以字节为单位)
pack_objects.compression_statistics 关于 pack-objects 生成的统计信息
pack_objects.enumerate_objects_ms 客户端发送的对象枚举所花费的总时间(毫秒)
pack_objects.prepare_pack_ms 在将包文件发回客户端之前准备包文件所花费的总时间(毫秒)
pack_objects.write_pack_file_ms 将包文件发回客户端所花费的总时间(毫秒)。高度依赖客户端的网络连接
pack_objects.written_object_count Gitaly 发送给客户端的对象总数

在以下情况下:

  • 缓存未命中:Gitaly 会同时记录 pack_objects_cache.generated_bytespack_objects_cache.served_bytes 消息。Gitaly 还会记录一些更详细的 pack-object 生成统计信息。
  • 缓存命中:Gitaly 仅记录 pack_objects_cache.served_bytes 消息。

示例:

{
  "bytes":26186490,
  "correlation_id":"01F1MY8JXC3FZN14JBG1H42G9F",
  "grpc.meta.deadline_type":"none",
  "grpc.method":"PackObjectsHook",
  "grpc.request.fullMethod":"/gitaly.HookService/PackObjectsHook",
  "grpc.request.glProjectPath":"root/gitlab-workhorse",
  "grpc.request.glRepository":"project-2",
  "grpc.request.repoPath":"@hashed/d4/73/d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35.git",
  "grpc.request.repoStorage":"default",
  "grpc.request.topLevelGroup":"@hashed",
  "grpc.service":"gitaly.HookService",
  "grpc.start_time":"2021-03-25T14:57:52.747Z",
  "level":"info",
  "msg":"finished unary call with code OK",
  "peer.address":"@",
  "pid":20961,
  "span.kind":"server",
  "system":"grpc",
  "time":"2021-03-25T14:57:53.543Z",
  "pack_objects.compression_statistics": "Total 145991 (delta 68), reused 6 (delta 2), pack-reused 145911",
  "pack_objects.enumerate_objects_ms": 170,
  "pack_objects.prepare_pack_ms": 7,
  "pack_objects.write_pack_file_ms": 786,
  "pack_objects.written_object_count": 145991,
  "pack_objects_cache.generated_bytes": 49533030,
  "pack_objects_cache.hit": "false",
  "pack_objects_cache.key": "123456789",
  "pack_objects_cache.served_bytes": 49533030,
  "peer.address": "127.0.0.1",
  "pid": 8813,
}

cat-file 缓存

许多 Gitaly RPC 需要从仓库中查找 Git 对象。大多数时候我们使用 git cat-file --batch 进程来实现这一点。为了更好的性能,Gitaly 可以跨 RPC 调用复用这些 git cat-file 进程。先前使用的进程会被保存在一个 git cat-file 缓存 中。为了控制这使用了多少系统资源,我们设置了可以进入缓存的 cat-file 进程的最大数量。

默认限制是 100 个 cat-file,它们构成一对 git cat-file --batchgit cat-file --batch-check 进程。如果你看到关于“打开文件过多”的错误,或无法创建新进程的情况,你可能需要降低这个限制。

理想情况下,该数字应足够大以处理标准流量。如果提高限制,你应该在调整前后测量缓存命中率。如果命中率没有改善,较高的限制可能不会产生实质性影响。以下是查看命中率的 Prometheus 查询示例:

sum(rate(gitaly_catfile_cache_total{type="hit"}[5m])) / sum(rate(gitaly_catfile_cache_total{type=~"(hit)|(miss)"}[5m]))

Gitaly 配置文件 中配置 cat-file 缓存。

配置 GitLab UI 提交的签名

在 GitLab 自托管版中,此功能默认可用。若要隐藏该功能,管理员可以 禁用名为 gitaly_gpg_signing 的功能标志。 在 GitLab.com 上,此功能不可用。在 GitLab 专用版上,此功能可用。

默认情况下,Gitaly 不会对通过 GitLab UI 进行的提交进行签名。例如,使用以下方式进行的提交:

  • Web 编辑器。
  • Web IDE。
  • 合并请求。

当你在 Gitaly 中启用提交签名时:

  • GitLab 会对所有通过 UI 进行的提交进行签名。
  • 签名会验证提交者的身份,而非作者的身份。
  • 你可以配置 Gitaly 以反映某个提交是由你的实例提交的,方法是设置 committer_emailcommitter_name。例如,在 GitLab.com 上,这些配置选项被设置为 [email protected]GitLab

rotated_signing_keys 是一个用于仅验证的密钥列表。Gitaly 会尝试使用配置好的 signing_key 来验证 Web 提交,如果失败,则依次使用旋转密钥直到成功。在以下情况时设置 rotated_signing_keys 选项:

  • 签名密钥已被轮换。
  • 你想指定多个密钥以迁移来自其他实例的项目,并希望将这些 Web 提交显示为 已验证

你可以通过以下两种方式之一配置 Gitaly 以对通过 GitLab UI 进行的提交进行签名:

  1. 创建 GPG 密钥 并导出它,或 创建 SSH 密钥。为了最佳性能,请使用 EdDSA 密钥。

    导出 GPG 密钥:

    gpg --export-secret-keys <ID> > signing_key.gpg

    或创建 SSH 密钥(无密码短语):

    ssh-keygen -t ed25519 -f signing_key.ssh
  2. 在 Gitaly 节点上,将密钥复制到 /etc/gitlab/gitaly/ 并确保 git 用户有读取文件的权限。

  3. 编辑 /etc/gitlab/gitlab.rb 并配置 gitaly['git']['signing_key']

    gitaly['configuration'] = {
       # ...
       git: {
         # ...
         committer_name: 'Your Instance',
         committer_email: '[email protected]',
         signing_key: '/etc/gitlab/gitaly/signing_key.gpg',
         rotated_signing_keys: ['/etc/gitlab/gitaly/previous_signing_key.gpg'],
         # ...
       },
    }
  4. 保存文件并 重新配置 GitLab

  1. 创建 GPG 密钥 并导出它,或 创建 SSH 密钥。为了最佳性能,请使用 EdDSA 密钥。

    导出 GPG 密钥:

    gpg --export-secret-keys <ID> > signing_key.gpg

    或创建 SSH 密钥(无密码短语):

    ssh-keygen -t ed25519 -f signing_key.ssh
  2. 在 Gitaly 节点上,将密钥复制到 /etc/gitlab

  3. 编辑 /home/git/gitaly/config.toml 并配置 signing_key

    [git]
    committer_name = "Your Instance"
    committer_email = "[email protected]"
    signing_key = "/etc/gitlab/gitaly/signing_key.gpg"
    rotated_signing_keys = ["/etc/gitlab/gitaly/previous_signing_key.gpg"]
  4. 保存文件并 重启 GitLab

使用外部命令生成配置

您可以使用外部命令生成 Gitaly 配置的一部分。您可能这样做:

  • 无需向每个节点分发完整配置即可配置节点。
  • 使用自动发现节点的设置来配置。例如,使用 DNS 条目。
  • 在节点启动时配置密钥,因此不需要以明文形式显示。

要使用外部命令生成配置,您必须提供一个脚本,该脚本将其标准输出中的 Gitaly 节点所需配置以 JSON 格式转储。

例如,以下命令使用 AWS 密钥配置用于连接到 GitLab 内部 API 的 HTTP 密码:

#!/usr/bin/env ruby
require 'json'
JSON.generate({"gitlab": {"http_settings": {"password": `aws get-secret-value --secret-id ...`}}})

然后,您必须通过以下两种方式之一让 Gitaly 知道脚本路径:

编辑 /etc/gitlab/gitlab.rb 并配置 config_command

gitaly['configuration'] = {
    config_command: '/path/to/config_command',
}

编辑 /home/git/gitaly/config.toml 并配置 config_command

config_command = "/path/to/config_command"

配置完成后,Gitaly 会在启动时执行该命令并将其标准输出解析为 JSON。然后将生成的配置合并回其他 Gitaly 配置中。

如果发生以下情况,Gitaly 将无法启动:

  • 配置命令失败。
  • 命令产生的输出无法解析为有效的 JSON。

配置服务器端备份

可以配置仓库备份,使托管每个仓库的 Gitaly 节点负责创建备份并将其流式传输到对象存储。这有助于减少创建和恢复备份所需的网络资源。

每个 Gitaly 节点都必须配置为连接到对象存储以进行备份。

配置服务器端备份后,您可以创建服务器端仓库备份

配置 Azure Blob 存储

如何为备份配置 Azure Blob 存储取决于您的安装类型。对于自编译安装,您必须在 GitLab 外部设置 AZURE_STORAGE_ACCOUNTAZURE_STORAGE_KEY 环境变量。

编辑 /etc/gitlab/gitlab.rb 并配置 go_cloud_url

gitaly['env'] = {
    'AZURE_STORAGE_ACCOUNT' => 'azure_storage_account',
    'AZURE_STORAGE_KEY' => 'azure_storage_key' # 或 'AZURE_STORAGE_SAS_TOKEN'
}
gitaly['configuration'] = {
    backup: {
        go_cloud_url: 'azblob://<bucket>'
    }
}

对于基于 Helm 的部署,请参阅Gitaly 图表的服务器端备份文档

编辑 /home/git/gitaly/config.toml 并配置 go_cloud_url

[backup]
go_cloud_url = "azblob://<bucket>"

配置 Google 云存储

Google 云存储 (GCP) 使用应用默认凭证进行身份验证。在每个 Gitaly 服务器上通过以下方式设置应用默认凭证:

更多信息请参阅 应用默认凭证

目标存储桶通过 go_cloud_url 选项配置。

编辑 /etc/gitlab/gitlab.rb 并配置 go_cloud_url

gitaly['env'] = {
    'GOOGLE_APPLICATION_CREDENTIALS' => '/path/to/service.json'
}
gitaly['configuration'] = {
    backup: {
        go_cloud_url: 'gs://<bucket>'
    }
}

对于基于 Helm 的部署,请参阅 Gitaly 图表的 server-side 备份文档

编辑 /home/git/gitaly/config.toml 并配置 go_cloud_url

[backup]
go_cloud_url = "gs://<bucket>"

配置 S3 存储

若要配置 S3 存储的身份验证:

  • 如果您使用 AWS CLI 进行身份验证,可以使用默认的 AWS 会话。
  • 否则,可使用 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY 环境变量。对于自行编译的安装,请在 GitLab 外部设置这些环境变量。

更多信息请参阅 AWS 会话文档

目标存储桶和区域通过 go_cloud_url 选项配置。

编辑 /etc/gitlab/gitlab.rb 并配置 go_cloud_url

gitaly['env'] = {
    'AWS_ACCESS_KEY_ID' => 'aws_access_key_id',
    'AWS_SECRET_ACCESS_KEY' => 'aws_secret_access_key'
}
gitaly['configuration'] = {
    backup: {
        go_cloud_url: 's3://<bucket>?region=us-west-1'
    }
}

对于基于 Helm 的部署,请参阅 Gitaly 图表的 server-side 备份文档

编辑 /home/git/gitaly/config.toml 并配置 go_cloud_url

[backup]
go_cloud_url = "s3://<bucket>?region=us-west-1"

配置 S3 兼容服务器

像 MinIO 这类 S3 兼容服务器的配置与 S3 类似,但需额外添加 endpoint 参数。

支持的参数如下:

  • region:AWS 区域。
  • endpoint:端点 URL。
  • disabledSSL:值为 true 时禁用 SSL。
  • s3ForcePathStyle:值为 true 时强制使用路径风格寻址。

对于基于 Helm 的部署,请参阅 Gitaly 图表的 server-side 备份文档

编辑 /etc/gitlab/gitlab.rb 并配置 go_cloud_url

gitaly['env'] = {
    'AWS_ACCESS_KEY_ID' => 'minio_access_key_id',
    'AWS_SECRET_ACCESS_KEY' => 'minio_secret_access_key'
}
gitaly['configuration'] = {
    backup: {
        go_cloud_url: 's3://<bucket>?region=minio&endpoint=my.minio.local:8080&disableSSL=true&s3ForcePathStyle=true'
    }
}

编辑 /home/git/gitaly/config.toml 并配置 go_cloud_url

[backup]
go_cloud_url = "s3://<bucket>?region=minio&endpoint=my.minio.local:8080&disableSSL=true&s3ForcePathStyle=true"