配置 Gitaly

可以通过以下两种方式配置 Gitaly:

::Tabs

:::TabTitle Linux package (Omnibus)

  1. 编辑 /etc/gitlab/gitlab.rb 并添加或更改 Gitaly 设置
  2. 保存文件并重新配置极狐GitLab

:::TabTitle Helm chart (Kubernetes)

  1. 配置 Gitaly chart
  2. 升级你的 Helm 发布

:::TabTitle Self-compiled (source)

  1. 编辑 /home/git/gitaly/config.toml 并添加或更改 Gitaly 设置
  2. 保存文件并重启极狐GitLab

::EndTabs

以下配置选项也是可用的:

关于 Gitaly 令牌

在整个 Gitaly 文档中提到的令牌只是管理员选择的一个任意密码。它与为极狐GitLab API 或其他类似的网络 API 创建的令牌无关。

在独立服务器上运行 Gitaly

默认情况下,Gitaly 在与 Gitaly 客户端相同的服务器上运行,并如上配置。单服务器安装最好使用此默认配置:

然而,Gitaly 可以部署到自己的服务器,这对于跨多个机器的极狐GitLab 安装是有益的。

note
当配置为在自己的服务器上运行时,Gitaly 服务器必须在集群中的 Gitaly 客户端之前进行升级
note
磁盘需求适用于 Gitaly 节点。

在独立服务器上设置 Gitaly 的过程是:

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

网络架构

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

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

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

两个 Gitaly 服务器和一个极狐GitLab Rails 交换信息。

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

在下面的章节中,我们描述了如何配置两个 Gitaly 服务器,使用秘密令牌 abc123secret

  • gitaly1.internal
  • gitaly2.internal

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

  • default
  • storage1
  • storage2

你可以根据需要使用尽可能少的一个服务器和一个仓库存储。

安装 Gitaly

使用以下任一方法在每个 Gitaly 服务器上安装 Gitaly:

  • Linux package 安装。下载并安装你想要的 Linux package,但不要提供 EXTERNAL_URL= 值。
  • Self-compiled 安装。按照安装 Gitaly中的步骤操作。

配置 Gitaly 服务器

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

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

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

为了在旋转 Gitaly 令牌时避免停机,你可以使用 gitaly['auth_transitioning'] 设置暂时禁用认证。有关更多信息,请参见启用认证过渡模式

配置认证

Gitaly 和极狐GitLab 使用两个共享秘密进行认证:

  • Gitaly 令牌:用于认证对 Gitaly 的 gRPC 请求。
  • 极狐GitLab Shell 令牌:用于从极狐GitLab Shell 到极狐GitLab 内部 API 的认证回调。

::Tabs

:::TabTitle Linux package (Omnibus)

  1. 要配置 Gitaly 令牌,编辑 /etc/gitlab/gitlab.rb

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

    • 方法 1(推荐):

      从 Gitaly 客户端复制 /etc/gitlab/gitlab-secrets.json 到 Gitaly 服务器(以及其他任何 Gitaly 客户端)上的相同路径。

    • 方法 2:

      编辑 /etc/gitlab/gitlab.rb

      gitlab_shell['secret_token'] = 'shellsecret'
      

:::TabTitle Self-compiled (source)

  1. 从 Gitaly 客户端复制 /home/git/gitlab/.gitlab_shell_secret 到 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

::EndTabs

配置 Gitaly 服务器

配置 Gitaly 服务器。

::Tabs

:::TabTitle Linux package (Omnibus)

  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` 将失败。这可以是你的 '前门' 极狐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 的回调:
    • 对于极狐GitLab 15.3 及更高版本,运行 sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml
    • 对于极狐GitLab 15.2 及更早版本,运行 sudo -u git -- /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml

:::TabTitle Self-compiled (source)

  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 的回调:
    • 对于极狐GitLab 15.3 及更高版本,运行 sudo -u git -- /opt/gitlab/embedded/bin/gitaly check /var/opt/gitlab/gitaly/config.toml
    • 对于极狐GitLab 15.2 及更早版本,运行 sudo -u git -- /opt/gitlab/embedded/bin/gitaly-hooks check /var/opt/gitlab/gitaly/config.toml

::EndTabs

caution
如果直接从极狐GitLab 服务器复制仓库数据到 Gitaly,请确保不在传输中包含元数据文件,默认路径 /var/opt/gitlab/git-data/repositories/.gitaly-metadata。复制此文件会导致极狐GitLab 使用直接磁盘访问托管在 Gitaly 服务器上的仓库,导致 Error creating pipelineCommit not found 错误,或数据过时。

配置 Gitaly 客户端

作为最后一步,您必须更新 Gitaly 客户端,以切换从使用本地 Gitaly 服务到使用您刚刚配置的 Gitaly 服务器。

note极狐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.internalgitaly2.internal Gitaly 服务器可以相互访问。

除非您使用 混合配置,否则不能定义某些作为本地 Gitaly 服务器(没有 gitaly_address)和某些作为远程服务器(具有 gitaly_address)的 Gitaly 服务器。

以两种方式之一配置 Gitaly 客户端。这些说明适用于未加密的连接,但您也可以启用 TLS 支持

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

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

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

    或者,如果每个 Gitaly 服务器配置使用不同的身份验证令牌:

    git_data_dirs({
      '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 客户端上运行 sudo gitlab-rake gitlab:gitaly:check(例如,Rails 应用程序)以确认它可以连接到 Gitaly 服务器。
  4. 跟踪日志以查看请求:

    sudo gitlab-ctl tail gitaly
    

:::TabTitle 自编译 (源代码)

  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
    

::EndTabs

当您在 Gitaly 服务器上跟踪 Gitaly 日志时,您应该会看到请求进来。触发 Gitaly 请求的一种确定方法是通过 HTTP 或 HTTPS 从极狐GitLab 克隆一个仓库。

caution如果您配置了 服务器钩子,无论是每个仓库还是全局,您必须将这些移动到 Gitaly 服务器。如果您有多个 Gitaly 服务器,请将您的服务器钩子复制到所有 Gitaly 服务器。

混合配置

极狐GitLab 可以与众多 Gitaly 服务器之一位于同一服务器上,但不支持将本地和远程配置混合的配置。以下设置不正确,因为:

  • 所有地址必须可从其他 Gitaly 服务器访问。
  • storage1 被分配了一个 Unix 套接字作为 gitaly_address,这对于某些 Gitaly 服务器来说是无效的。
git_data_dirs({
  'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
  'storage1' => { 'path' => '/mnt/gitlab/git-data' },
  'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
})

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

git_data_dirs({
  'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
  # 运行极狐GitLab 的服务器地址也运行 Gitaly
  '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 应用程序服务器以从 git_data_dirs 中删除 default 条目,因为极狐GitLab 需要一个名为 defaultgit_data_dirs 条目。

要解决此限制:

  1. 在新的 Gitaly 服务上定义一个附加的存储位置,并将附加的存储配置为 default
  2. 管理员区域中,将 default 设置为零权重以防止仓库存储在那里。

在不需要的地方禁用 Gitaly(可选)

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

仅当您在自定义集群配置中运行极狐GitLab 时,在极狐GitLab 实例上禁用 Gitaly 才有意义,其中 Gitaly 运行在与极狐GitLab 实例不同的机器上。在集群中的所有机器上禁用 Gitaly 不是一个有效的配置(某些机器必须充当 Gitaly 服务器)。

以两种方式之一在极狐GitLab 服务器上禁用 Gitaly:

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

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

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

:::TabTitle 自编译 (源代码)

  1. 编辑 /etc/default/gitlab

    gitaly_enabled=false
    
  2. 保存文件并重新启动极狐GitLab

::EndTabs

控制组

caution 在您的环境中启用限制应谨慎行事,并且仅在特定情况下进行,例如防止意外流量。当达到时,限制确实会导致断开连接,给用户带来负面影响。为了获得一致和稳定的性能,您应首先探索其他选项,例如调整节点规格,以及审查大型仓库或工作负载。

在为内存启用 cgroups 时,您应确保在 Gitaly 节点上未配置交换,因为进程可能会改为使用该交换而不是被终止。这种情况可能导致性能显著下降。

您可以在 Linux 中使用控制组(cgroups)对 Gitaly 进程可以消耗的内存和 CPU 施加限制。cgroups 可以帮助保护系统免受由于内存和 CPU 过度消耗而导致的意外资源耗尽。

一些 Git 操作在某些情况下可能会消耗显著的资源,直到耗尽,例如:

  • 意外的高流量。
  • 针对不遵循最佳实践的大型仓库运行的操作。

作为一种硬保护,可以使用 cgroups 配置内核以在这些操作占用所有系统资源并导致不稳定之前终止它们。

Gitaly 具有内置的 cgroups 控制功能。配置后,Gitaly 会根据 Git 命令所在的仓库将 Git 进程分配给一个 cgroup。每个仓库 cgroup:

  • 具有内存和 CPU 限制。
  • 包含单个仓库的 Git 进程。
  • 使用一致的哈希确保给定仓库的 Git 进程始终位于同一个 cgroup 中。

当仓库 cgroup 达到其:

  • 内存限制时,内核会查看进程以寻找要终止的候选进程。
  • CPU 限制时,进程不会被终止,但会被阻止消耗超过允许的 CPU。
note当达到这些限制时,性能可能会降低,用户可能会断开连接。

配置仓库 cgroups(新方法)

  • 配置仓库 cgroups 的这种方法在极狐GitLab 15.1 中引入。
  • cpu_quota_us 在极狐GitLab 15.10 中引入。
  • max_cgroups_per_repo 在极狐GitLab 16.7 中引入。

要使用新方法在 Gitaly 中配置仓库 cgroups,请使用以下设置为 /etc/gitlab/gitlab.rb 中的 gitaly['configuration'][:cgroups] 使用新配置方法:

  • mountpoint 是父 cgroup 目录的挂载点。默认为 /sys/fs/cgroup
  • hierarchy_root 是 Gitaly 创建组的父 cgroup,预计由 Gitaly 运行的用户和组拥有。Linux 软件包安装在 Gitaly 启动时创建目录 mountpoint/<cpu|memory>/hierarchy_root
  • memory_bytes 是对 Gitaly 生成的所有 Git 进程施加的总内存限制。0 表示无限制。
  • cpu_shares 是对 Gitaly 生成的所有 Git 进程施加的 CPU 限制。0 表示无限制。最大值为 1024 份,代表 100% 的 CPU。
  • cpu_quota_us 是用于节流 cgroups 进程的 cfs_quota_us 配置项。如果超过此配额值,我们设置 cfs_period_us100ms,因此 1 核心为 100000。0 表示无限制。
  • repositories.count 是 cgroups 池中的 cgroups 数量。每次生成新的 Git 命令时,Gitaly 都会根据命令所属的仓库将其分配给其中一个 cgroups。循环散列算法将 Git 命令分配给这些 cgroups,因此给定仓库的 Git 命令始终分配给同一个 cgroup。
  • repositories.memory_bytes 是对存储在仓库 cgroup 中的所有 Git 进程施加的总内存限制。0 表示无限制。此值不能超过顶级 memory_bytes 的值。
  • repositories.cpu_shares 是对存储在仓库 cgroup 中的所有 Git 进程施加的 CPU 限制。0 表示无限制。最大值为 1024 份,代表 100% 的 CPU。此值不能超过顶级 cpu_shares 的值。
  • repositories.cpu_quota_us 是对存储在仓库 cgroup 中的所有 Git 进程施加的 cfs_quota_us。Git 进程不能使用超过给定配额。我们设置 cfs_period_us100ms,因此 1 核心为 100000。0 表示无限制。
  • repositories.max_cgroups_per_repo 是针对特定仓库的 Git 进程可以分布在的仓库 cgroups 的数量。这使得可以为仓库 cgroups 配置更保守的 CPU 和内存限制,同时仍然允许突发工作负载。例如,设置 max_cgroups_per_repo2memory_bytes 限制为 10GB,针对特定仓库的独立 Git 操作最多可以消耗 20GB 的内存。

例如(不一定推荐设置):

# 在 /etc/gitlab/gitlab.rb 中
gitaly['configuration'] = {
  # ...
  cgroups: {
    mountpoint: '/sys/fs/cgroup',
    hierarchy_root: 'gitaly',
    memory_bytes: 64424509440, # 60gb
    cpu_shares: 1024,
    cpu_quota_us: 400000 # 4 cores
    repositories: {
      count: 1000,
      memory_bytes: 32212254720, # 20gb
      cpu_shares: 512,
      cpu_quota_us: 200000, # 2 cores
      max_cgroups_per_repo: 2
    },
  },
}

配置仓库 cgroups(传统方法)

要使用传统方法在 Gitaly 中配置仓库 cgroups,请在 /etc/gitlab/gitlab.rb 中使用以下设置:

  • cgroups_count 是创建的 cgroups 数量。每次生成新的命令时,Gitaly 根据命令的命令行参数将其分配给其中一个 cgroups。循环散列算法将命令分配给这些 cgroups。
  • cgroups_mountpoint 是父 cgroup 目录的挂载点。默认为 /sys/fs/cgroup
  • cgroups_hierarchy_root 是 Gitaly 创建组的父 cgroup,预计由 Gitaly 运行的用户和组拥有。Linux 软件包安装在 Gitaly 启动时创建目录 mountpoint/<cpu|memory>/hierarchy_root
  • cgroups_memory_enabled 启用或禁用 cgroups 的内存限制。
  • cgroups_memory_bytes 是每个 cgroup 对其添加的进程施加的总内存限制。
  • cgroups_cpu_enabled 启用或禁用 cgroups 的 CPU 限制。
  • cgroups_cpu_shares 是每个 cgroup 对其添加的进程施加的 CPU 限制。最大值为 1024 份,代表 100% 的 CPU。

例如:

# 在 /etc/gitlab/gitlab.rb 中
gitaly['cgroups_count'] = 1000
gitaly['cgroups_mountpoint'] = "/sys/fs/cgroup"
gitaly['cgroups_hierarchy_root'] = "gitaly"
gitaly['cgroups_memory_limit'] = 32212254720
gitaly['cgroups_memory_enabled'] = true
gitaly['cgroups_cpu_shares'] = 1024
gitaly['cgroups_cpu_enabled'] = true

配置超量订阅

在使用新配置方法的前一个示例中:

  • 顶级内存限制被限制为 60 GB。
  • 仓库池中的 1000 个 cgroups 中的每一个都被限制为 20 GB。

此配置导致超量订阅。池中的每个 cgroup 的容量远大于顶级内存限制的 1/1000。

这种策略有两个主要好处:

  • 它可以保护主机免受整体内存匮乏(OOM),因为顶级 cgroup 的内存限制可以设置为小于主机容量的阈值。在该 cgroup 之外的进程不会面临 OOM 的风险。
  • 它允许池中的每个单独 cgroup 爆发到一个慷慨的上限(在此示例中为 20 GB),该上限小于父 cgroup 的限制,但大大超过父 cgroup 限制的 1/N。在此示例中,最多 3 个子 cgroups 可以同时爆发到其最大值。通常,所有 1000 个 cgroups 使用的内存远小于 20 GB。

背景仓库优化

在仓库中可能会积累空目录和不需要的配置设置,从而减慢 Git 操作的速度。Gitaly 可以安排一个每日背景任务,设置最大持续时间,以清理这些项目并提高性能。

caution背景仓库优化是一个实验功能,运行时可能会给主机带来显著负载。请确保在非高峰时段进行调度,并保持持续时间较短(例如 30-60 分钟)。

以两种方式之一配置背景仓库优化:

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

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

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

:::TabTitle 自编译 (源代码)

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

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

::EndTabs

轮换 Gitaly 身份验证令牌

在生产环境中轮换凭据通常需要停机时间、导致中断或两者兼而有之。

但是,您可以在不中断服务的情况下轮换 Gitaly 凭据。轮换 Gitaly 身份验证令牌涉及:

如果您在单台服务器上运行极狐GitLab,此过程同样适用。在这种情况下,Gitaly 服务器和 Gitaly 客户端指的是同一台机器。

验证身份验证监控

在轮换 Gitaly 身份验证令牌之前,请验证您可以使用 Prometheus 监控极狐GitLab 安装的身份验证行为

然后您可以继续执行该过程的其余部分。

启用身份验证过渡模式

通过将 Gitaly 服务器置于身份验证过渡模式来暂时禁用 Gitaly 身份验证,具体如下:

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

在您进行此更改后,您的 Prometheus 查询 应返回类似以下内容:

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

因为 enforced="false",所以开始推出新令牌是安全的。

更新 Gitaly 身份验证令牌

要更新为新的 Gitaly 身份验证令牌,请在每个 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 客户端和 Gitaly 服务器拾取新令牌后,唯一的非零率应该是 enforced="false",status="would be ok"

禁用身份验证过渡模式

要重新启用 Gitaly 身份验证,请禁用身份验证过渡模式。在 Gitaly 服务器上更新配置如下:

# 在 /etc/gitlab/gitlab.rb 中
gitaly['configuration'] = {
  # ...
  auth: {
    # ...
    transitioning: false,
  },
}
caution 如果不完成此步骤,您将没有 Gitaly 身份验证

验证身份验证已强制执行

刷新您的 Prometheus 查询。您现在应该看到与开始时相似的结果。例如:

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

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

打包对象缓存

Gitaly,提供 Git 仓库存储的服务,可以配置为缓存 Git 提取响应的短滚动窗口。这可以在服务器收到大量 CI 提取流量时减少服务器负载。

打包对象缓存封装了 git pack-objects,它是 Git 的内部部分,通过使用 PostUploadPack 和 SSHUploadPack Gitaly RPC 间接调用。当用户通过 HTTP 执行 Git 提取时,Gitaly 运行 PostUploadPack,或者当用户通过 SSH 执行 Git 提取时,运行 SSHUploadPack。当缓存启用时,任何使用 PostUploadPack 或 SSHUploadPack 的操作都可以从中受益。它与以下无关:

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

此缓存的优势在于它能够去重并发的相同提取。它:

  • 可以使您的用户运行许多并发作业的 CI/CD 流水线的极狐GitLab 实例受益。服务器 CPU 利用率应显著降低。
  • 对于唯一的提取没有任何益处。例如,如果您通过克隆仓库到本地计算机进行抽查,您不太可能从此缓存中看到好处,因为您的提取可能是唯一的。

打包对象缓存是本地缓存。它:

  • 将其元数据存储在启用的 Gitaly 进程的内存中。
  • 将其缓存的实际 Git 数据存储在本地存储的文件中。

使用本地文件的好处是操作系统可以自动将打包对象缓存文件的部分保存在 RAM 中,使其速度更快。

由于打包对象缓存可能导致磁盘写入 IO 显著增加,因此默认情况下是关闭的。在极狐GitLab 15.11 及更高版本中,写入工作负载减少了约 50%,但缓存仍然默认禁用。

配置缓存

以下是打包对象缓存可用的配置设置。每个设置在下文中详细讨论。

Setting Default Description
enabled false 启用缓存。当关闭时,Gitaly 为每个请求运行一个专用的 git pack-objects 进程。
dir <PATH TO FIRST STORAGE>/+gitaly/PackObjectsCache 缓存文件存储的本地目录。
max_age 5m (5 分钟) 超过此时间的缓存条目将被逐出并从磁盘中删除。
min_occurrences 1 创建缓存条目前的最小键出现次数。

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

gitaly['configuration'] = {
  # ...
  pack_objects_cache: {
    # ...
    enabled: true,
    # dir: '/var/opt/gitlab/git-data/repositories/+gitaly/PackObjectsCache',
    # max_age: '5m',
    # min_occurrences: 1,
  },
}

enabled 默认为 false

缓存默认情况下是禁用的,因为在某些情况下,它可能会导致磁盘写入字节的极端增加。在 GitLab.com,我们已经验证了我们的仓库存储磁盘可以处理这种额外的工作负载,但我们认为不能假设其他地方也会这样。

缓存存储目录 dir

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

  • 位于具有足够空间的文件系统中。如果缓存文件系统空间不足,所有提取将开始失败。
  • 位于具有足够 IO 带宽的磁盘上。如果缓存磁盘 IO 带宽不足,所有提取以及可能整个服务器都会变慢。

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

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

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

虽然默认目录将缓存文件放在与您的仓库数据相同的文件系统中,但这不是必需的。您可以将缓存文件放在不同的文件系统中,如果这更适合您的基础设施。

所需的 IO 带宽量取决于:

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

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

所需的空间量取决于:

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

如果您的用户每秒提取 100 MB,并且您使用 5 分钟窗口,那么平均而言,您的缓存目录中会有 5*60*100MB = 30GB 的数据。此平均值是预期的平均值,而不是保证。峰值大小可能会超过此平均值。

缓存逐出窗口 max_age

max_age 配置设置让您可以控制缓存命中的机会和缓存文件所用的平均存储量。超过 max_age 的条目将从磁盘中删除。

逐出不会干扰正在进行的请求。即使 max_age 小于通过慢速连接进行提取所需的时间也是可以的,因为 Unix 文件系统在所有正在读取删除文件的进程关闭该文件之前不会真正删除文件。

最小键出现次数 min_occurrences

  • 在极狐GitLab 15.11 中引入。

min_occurrences 设置控制相同请求必须出现的频率,才能创建新的缓存条目。默认值为 1,这意味着唯一请求不会被写入缓存。

如果您:

  • 增加此数字,您的缓存命中率会下降,缓存使用的磁盘空间会减少。
  • 减少此数字,您的缓存命中率会上升,缓存使用的磁盘空间会增加。

您应将 min_occurrences 设置为 1。在 GitLab.com,从 0 到 1 节省了我们 50% 的缓存磁盘空间,同时几乎没有影响缓存命中率。

观察缓存

  • 极狐GitLab 16.0 中更改了打包对象缓存的日志。

您可以使用指标和以下记录的信息来观察缓存。这些日志是 gRPC 日志的一部分,可以在调用执行时发现。

Field Description
pack_objects_cache.hit 表示当前打包对象缓存是否命中(truefalse
pack_objects_cache.key 用于打包对象缓存的缓存键
pack_objects_cache.generated_bytes 正在写入的新缓存的大小(以字节为单位)
pack_objects_cache.served_bytes 正在提供的缓存的大小(以字节为单位)
pack_objects.compression_statistics 关于打包对象生成的统计信息
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 还会记录一些关于打包对象生成的更详细的统计信息。
  • 缓存命中,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 15.4 中引入。
  • 在极狐GitLab 16.3 中引入显示 已验证 徽章的功能标志名为 gitaly_gpg_signing。默认情况下禁用。
  • 在极狐GitLab 16.3 中通过 rotated_signing_keys 选项引入的使用多个密钥验证签名。
  • 在极狐GitLab 17.0 中默认启用的私有化部署和极狐GitLab 专属版中。
在私有化部署的极狐GitLab 中,默认情况下此功能可用。要隐藏此功能,管理员可以禁用功能标志名为 gitaly_gpg_signing。在 GitLab.com 中,此功能不可用。在极狐GitLab 专属版中,此功能可用。

默认情况下,Gitaly 不会为使用极狐GitLab UI 制作的提交签名。例如,使用以下方式制作的提交:

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

您可以配置 Gitaly 为使用极狐GitLab UI 制作的提交签名。

默认情况下,Gitaly 将提交的作者设置为提交者。在这种情况下,本地验证提交比较困难,因为签名既不属于提交的作者,也不属于提交者。

您可以配置 Gitaly 以反映提交已由您的实例提交,通过设置 committer_emailcommitter_name。例如,在 GitLab.com 上,这些配置选项设置为 noreply@gitlab.comGitLab

rotated_signing_keys 是仅用于验证的密钥列表。Gitaly 尝试使用配置的 signing_key 验证 Web 提交,然后逐个使用轮换的密钥,直到成功。设置 rotated_signing_keys 选项的情况包括:

  • 签名密钥已轮换。
  • 您希望指定多个密钥以从其他实例迁移项目,并希望将其 Web 提交显示为 已验证

以两种方式之一配置 Gitaly 以为使用极狐GitLab UI 制作的提交签名:

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

  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/
  3. 编辑 /etc/gitlab/gitlab.rb 并配置 gitaly['git']['signing_key']

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

:::TabTitle 自编译 (源代码)

  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 = "noreply@yourinstance.com"
    signing_key = "/etc/gitlab/gitaly/signing_key.gpg"
    rotated_signing_keys = ["/etc/gitlab/gitaly/previous_signing_key.gpg"]
    
  4. 保存文件并重新启动极狐GitLab

::EndTabs

使用外部命令生成配置

  • 在极狐GitLab 15.11 中引入。

您可以使用外部命令生成 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 知道脚本路径:

::Tabs

:::TabTitle Linux 软件包 (Omnibus)

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

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

:::TabTitle 自编译 (源代码)

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

config_command = "/path/to/config_command"

::EndTabs