Gitaly

Gitaly

是提供对 Git 存储库的高级 RPC 访问的服务. 没有它,任何 GitLab 组件都无法读取或写入 Git 数据.

在 Gitaly 文档中:

GitLab 最终用户无法直接访问 Gitaly. Gitaly 仅管理 GitLab 的 Git 存储库访问. 其他类型的 GitLab 数据无法使用 Gitaly 访问.

警告:从 GitLab 13.0 起,不支持 Gitaly 对 NFS 的支持. 在 GitLab 14.0 中,计划删除对 NFS 的 Gitaly 支持. 尽快升级到 .

以下是有关如何使用 Gitaly 的高级体系结构概述.

Configure Gitaly

Gitaly 服务本身是通过TOML 配置文件配置的 .

要更改 Gitaly 设置,请执行以下操作:

对于所有 GitLab

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

对于源安装

  1. 编辑/home/git/gitaly/config.toml并添加或更改 .
  2. 保存文件并重新启动 GitLab .

以下配置选项也可用:

Run Gitaly on its own server

默认情况下,Gitaly 与 Gitaly 客户端在同一服务器上运行,并按上述配置 . 单服务器安装最好由以下默认配置使用:

However, Gitaly can be deployed to its own server, which can benefit GitLab installations that span multiple machines.

注意:配置为在自己的服务器上运行时, Gitaly 服务器,然后才能在群集中的 Gitaly 客户端上进行升级 .

在自己的服务器上设置 Gitaly 的过程是:

  1. .
  2. Configure authentication.
  3. .
  4. Configure Gitaly clients.
  5. (optional).

在自己的服务器上运行 Gitaly 时,请注意有关 GitLab 版本的以下内容:

  • 从 GitLab 11.4 起,除了Elasticsearch indexer之外,Gitaly 能够满足所有 Git 请求,而无需为 Git 存储库数据共享 NFS 挂载.
  • 从 GitLab 11.8 开始,Elasticsearch 索引器还使用 Gitaly 进行数据访问. NFS 仍可用于块级 Git 数据的冗余,但仅需安装在 Gitaly 服务器上.
  • 从 GitLab 11.8 到 12.2,可以在不使用 NFS 的 Gitaly 设置中使用 Elasticsearch. 为了在这些版本中使用 Elasticsearch,必须在您的 GitLab 配置中启用 .
  • 从 GitLab 12.3 开始 ,新的索引器是默认的,不需要任何配置.

以下列表描述了 Gitaly 的网络体系结构:

  • GitLab Rails shards repositories into .
  • /config/gitlab.yml包含从存储名称到(Gitaly address, Gitaly token)对的(Gitaly address, Gitaly token) .
  • /config/gitlab.ymlstorage name -> (Gitaly address, Gitaly token)映射是 Gitaly 网络拓扑的唯一事实来源.
  • (Gitaly address, Gitaly token)对应于 Gitaly 服务器.
  • Gitaly 服务器托管一个或多个存储.
  • 一个 Gitaly 客户端可以使用一个或多个 Gitaly 服务器.
  • 必须以对所有 Gitaly 客户端正确解析的方式指定 Gitaly 地址.
  • Gitaly 客户包括:
    • 美洲狮或独角兽.
    • Sidekiq.
    • 亚搏体育 app Labhorse.
    • GitLab 外壳.
    • Elasticsearch 索引器.
    • Gitaly 本身.
  • 一个 Gitaly 服务器必须能够通过其自身发出 RPC 调用本身 (Gitaly address, Gitaly token)在指定的一对/config/gitlab.yml .
  • 认证通过静态令牌完成,该令牌在 Gitaly 和 GitLab Rails 节点之间共享.

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

在以下各节中,我们描述如何使用秘密令牌abc123secret配置两个 Gitaly 服务器:

  • gitaly1.internal.
  • gitaly2.internal.

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

  • default.
  • storage1.
  • storage2.

如果需要,一台服务器最多只能使用一个存储库.

注意: Gitaly 文档中引用的令牌只是管理员选择的任意密码. 它与为 GitLab API 创建的令牌或其他类似的 Web API 令牌无关.

Install Gitaly

使用 Omnibus GitLab 在每台 Gitaly 服务器上安装 Gitaly 或从源代码安装它:

  • 对于 Omnibus GitLab,请下载并安装所需的 Omnibus GitLab 软件包,但不要提供EXTERNAL_URL=值.
  • 要从源代码安装,请遵循的步骤.

Configure authentication

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

  • 一种用于向 Gitaly 验证 gRPC 请求的身份.
  • A second for authentication callbacks from GitLab Shell to the GitLab internal API.

对于所有 GitLab

要配置 Gitaly 令牌:

  1. 在 Gitaly 客户端上,编辑/etc/gitlab/gitlab.rb

  2. 保存文件并 .

  3. 在 Gitaly 服务器上,编辑/etc/gitlab/gitlab.rb

    1. gitaly['auth_token'] = 'abc123secret'
  4. Reconfigure GitLab.

有两种方法可以配置 GitLab Shell 令牌.

方法 1:

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

方法 2:

  1. 在 Gitaly 客户端上,编辑/etc/gitlab/gitlab.rb

    1. gitlab_shell['secret_token'] = 'shellsecret'
  2. 保存文件并重新配置 GitLab .

  3. 在 Gitaly 服务器上,编辑/etc/gitlab/gitlab.rb

    1. gitlab_shell['secret_token'] = 'shellsecret'
  4. .

对于源安装

  1. /home/git/gitlab/.gitlab_shell_secret从 Gitaly 客户端复制到 Gitaly 服务器(和任何其他 Gitaly 客户端)上的相同路径.
  2. 在 Gitaly 客户端上,编辑/home/git/gitlab/config/gitlab.yml

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

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

    1. [auth]
    2. token = 'abc123secret'
  5. 保存文件并 .

Configure Gitaly servers

在 Gitaly 服务器上,您必须配置存储路径并启用网络侦听器.

如果要减少启用身份验证时发生停机的风险,可以暂时禁用强制实施. 有关更多信息,请参阅有关配置的文档.

对于所有 GitLab

  1. Edit /etc/gitlab/gitlab.rb:

    1. # /etc/gitlab/gitlab.rb
    2. # Avoid running unnecessary services on the Gitaly server
    3. postgresql['enable'] = false
    4. redis['enable'] = false
    5. nginx['enable'] = false
    6. puma['enable'] = false
    7. sidekiq['enable'] = false
    8. gitlab_workhorse['enable'] = false
    9. grafana['enable'] = false
    10. gitlab_exporter['enable'] = false
    11. # If you run a separate monitoring node you can disable these services
    12. prometheus['enable'] = false
    13. # If you don't run a separate monitoring node you can
    14. # enable Prometheus access & disable these extra services.
    15. # This makes Prometheus listen on all interfaces. You must use firewalls to restrict access to this address/port.
    16. # prometheus['listen_address'] = '0.0.0.0:9090'
    17. # prometheus['monitor_kubernetes'] = false
    18. # If you don't want to run monitoring services uncomment the following (not recommended)
    19. # node_exporter['enable'] = false
    20. # Prevent database connections during 'gitlab-ctl reconfigure'
    21. gitlab_rails['rake_cache_clear'] = false
    22. gitlab_rails['auto_migrate'] = false
    23. # Configure the gitlab-shell API callback URL. Without this, `git push` will
    24. # fail. This can be your 'front door' GitLab URL or an internal load
    25. # balancer.
    26. # Don't forget to copy `/etc/gitlab/gitlab-secrets.json` from Gitaly client to Gitaly server.
    27. gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
    28. # Make Gitaly accept connections on all network interfaces. You must use
    29. # firewalls to restrict access to this address/port.
    30. # Comment out following line if you only want to support TLS connections
    31. gitaly['listen_addr'] = "0.0.0.0:8075"
  2. 对于每个相应的 Gitaly 服务器,将以下内容附加到/etc/gitlab/gitlab.rb

    On gitaly1.internal:

    1. git_data_dirs({
    2. 'default' => {
    3. 'path' => '/var/opt/gitlab/git-data'
    4. },
    5. 'storage1' => {
    6. 'path' => '/mnt/gitlab/git-data'
    7. },
    8. })

    On gitaly2.internal:

    1. git_data_dirs({
    2. 'storage2' => {
    3. 'path' => '/srv/gitlab/git-data'
    4. },
    5. })
  3. 保存文件并重新配置 GitLab .

  4. 运行sudo /opt/gitlab/embedded/service/gitlab-shell/bin/check -config /opt/gitlab/embedded/service/gitlab-shell/config.yml以确认 Gitaly 可以执行对 GitLab 内部 API 的回调.

对于源安装

  1. Edit /home/git/gitaly/config.toml:

    1. listen_addr = '0.0.0.0:8075'
    2. internal_socket_dir = '/var/opt/gitlab/gitaly'
    3. [logging]
    4. format = 'json'
    5. level = 'info'
    6. dir = '/var/log/gitaly'
  2. 对于每个相应的 Gitaly 服务器,将以下内容附加到/home/git/gitaly/config.toml

    On gitaly1.internal:

    1. [[storage]]
    2. name = 'default'
    3. path = '/var/opt/gitlab/git-data/repositories'
    4. [[storage]]
    5. name = 'storage1'
    6. path = '/mnt/gitlab/git-data/repositories'

    On gitaly2.internal:

    1. [[storage]]
    2. name = 'storage2'
    3. path = '/srv/gitlab/git-data/repositories'
  3. Edit /home/git/gitlab-shell/config.yml:

    1. gitlab_url: https://gitlab.example.com
  4. 保存文件并 .

  5. 运行sudo -u git /home/git/gitlab-shell/bin/check -config /home/git/gitlab-shell/config.yml以确认 Gitaly 可以执行对 GitLab 内部 API 的回调.

Configure Gitaly clients

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

这可能会有风险,因为任何阻止您的 Gitaly 客户端访问 Gitaly 服务器的操作都将导致所有 Gitaly 请求失败. 例如,任何类型的网络,防火墙或名称解析问题.

此外,如果以前手动启用,则必须 .

Gitaly 作以下假设:

  • gitaly1.internal Gitaly 服务器可以达到gitaly1.internal:8075从 Gitaly 客户端,以及 Gitaly 服务器可以读取和写入/mnt/gitlab/default/mnt/gitlab/storage1 .
  • gitaly2.internal Gitaly 服务器可以达到gitaly2.internal:8075从 Gitaly 客户端,以及 Gitaly 服务器可以读取和写入/mnt/gitlab/storage2 .
  • 您的gitaly1.internalgitaly2.internal Gitaly 服务器可以相互访问.

除非您使用特殊的混合配置进行设置,否则不能将 Gitaly 服务器定义为本地 Gitaly 服务器(不带 ),而gitaly_address一些服务器定义为远程服务器(带gitaly_address ).

对于所有 GitLab

  1. Edit /etc/gitlab/gitlab.rb:

    1. git_data_dirs({
    2. 'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
    3. 'storage1' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
    4. 'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
    5. })
  2. 保存文件并 .

  3. 运行sudo gitlab-rake gitlab:gitaly:check确认 Gitaly 客户端可以连接到 Gitaly 服务器.
    1. sudo gitlab-ctl tail gitaly

对于源安装

  1. Edit /home/git/gitlab/config/gitlab.yml:

    1. gitlab:
    2. repositories:
    3. storages:
    4. default:
    5. gitaly_address: tcp://gitaly1.internal:8075
    6. path: /some/dummy/path
    7. storage1:
    8. gitaly_address: tcp://gitaly1.internal:8075
    9. path: /some/dummy/path
    10. storage2:
    11. gitaly_address: tcp://gitaly2.internal:8075
    12. path: /some/dummy/path

    注意: /some/dummy/path应该设置为存在的本地文件夹,但是该文件夹中不会存储任何数据. 解决此问题后,将不再需要 .

  2. Save the file and restart GitLab.
  3. 运行sudo -u git -H bundle exec rake gitlab:gitaly:check RAILS_ENV=production确认 Gitaly 客户端可以连接到 Gitaly 服务器.
  4. 拖尾日志以查看请求:

    1. tail -f /home/git/gitlab/log/gitaly.log

尾随 Gitaly 服务器上的 Gitaly 登录时,您应该会看到请求进入.触发 Gitaly 请求的一种可靠方法是通过 HTTP 或 HTTPS 从 GitLab 克隆存储库.

危险:如果已针对每个存储库或全局配置了 ,则必须将它们移至 Gitaly 服务器. 如果您有多个 Gitaly 服务器,则将服务器挂钩复制到所有 Gitaly 服务器.

Mixed configuration

GitLab 可以与许多 Gitaly 服务器之一驻留在同一服务器上,但是不支持混合本地和远程配置的配置. 以下设置不正确,因为:

  • 所有地址都必须可从其他 Gitaly 服务器访问.
  • storage1分配了一个gitaly_address Unix 套接字,该套接字对于某些 Gitaly 服务器无效.
  1. git_data_dirs({
  2. 'default' => { 'gitaly_address' => 'tcp://gitaly1.internal:8075' },
  3. 'storage1' => { 'path' => '/mnt/gitlab/git-data' },
  4. 'storage2' => { 'gitaly_address' => 'tcp://gitaly2.internal:8075' },
  5. })

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

path只能包含在本地 Gitaly 服务器上的存储分片中. 如果不包含,则默认的 Git 存储目录将用于该存储碎片.

Disable Gitaly where not required (optional)

如果您将 Gitaly 作为远程服务运行,则可能要禁用默认情况下在您的 GitLab 服务器上运行的本地 Gitaly 服务,而仅在需要时运行它.

仅当您在自定义群集配置中运行 GitLab 时,才在 GitLab 实例上禁用 Gitaly 才有意义,在该配置中,Gitaly 在与 GitLab 实例不同的机器上运行. 在群集中的所有计算机上禁用 Gitaly 并不是有效的配置(某些计算机充当 Gitaly 服务器).

To disable Gitaly on a GitLab server:

对于所有 GitLab

  1. Edit /etc/gitlab/gitlab.rb:

    1. gitaly['enable'] = false
  2. 保存文件并 .

对于源安装

  1. Edit /etc/default/gitlab:

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

在 GitLab 11.8 中 .

Gitaly 支持 TLS 加密. 要与侦听安全连接的 Gitaly 实例进行通信,必须在 GitLab 配置中相应存储条目的gitaly_address中使用tls:// URL 方案.

您必须提供自己的证书,因为不会自动提供. 与每个 Gitaly 服务器相对应的证书必须安装在该 Gitaly 服务器上.

此外,证书(或其证书颁发机构)必须安装在所有以下组件上:

  • Gitaly 服务器,包括使用证书的 Gitaly 服务器.
  • 与之通信的 Gitaly 客户.

该过程记录在GitLab 自定义证书配置中,并在下面重复进行.

请注意以下几点:

  • 证书必须指定用于访问 Gitaly 服务器的地址. 如果你是:
    • 通过主机名寻址 Gitaly 服务器,您可以为此使用”公用名”字段,也可以将其添加为”使用者备用名”.
    • 通过其 IP 地址寻址 Gitaly 服务器,必须将其作为主题备用名称添加到证书中. .
  • 您可以同时为 Gitaly 服务器配置未加密的侦听地址listen_addr和已加密的侦听地址tls_listen_addr . 这使您可以根据需要从未加密的流量逐渐过渡到加密的流量.

要使用 TLS 配置 Gitaly:

对于所有 GitLab

  1. 为 Gitaly 服务器创建证书.
  2. 在 Gitaly 客户端上,将证书(或其证书颁发机构)复制到/etc/gitlab/trusted-certs

    1. sudo cp cert.pem /etc/gitlab/trusted-certs/
  3. 在 Gitaly 客户端上,如下所示在/etc/gitlab/gitlab.rb编辑git_data_dirs

    1. git_data_dirs({
    2. 'default' => { 'gitaly_address' => 'tls://gitaly1.internal:9999' },
    3. 'storage1' => { 'gitaly_address' => 'tls://gitaly1.internal:9999' },
    4. 'storage2' => { 'gitaly_address' => 'tls://gitaly2.internal:9999' },
    5. })
  4. 保存文件并重新配置 GitLab .

  5. 在 Gitaly 服务器上,创建/etc/gitlab/ssl目录,然后在其中复制密钥和证书:

    1. sudo mkdir -p /etc/gitlab/ssl
    2. sudo chmod 755 /etc/gitlab/ssl
    3. sudo cp key.pem cert.pem /etc/gitlab/ssl/
    4. sudo chmod 644 key.pem cert.pem
  6. 将所有 Gitaly 服务器证书(或其证书颁发机构)复制到/etc/gitlab/trusted-certs以便 Gitaly 服务器在调用自身或其他 Gitaly 服务器时将信任该证书:

    1. sudo cp cert1.pem cert2.pem /etc/gitlab/trusted-certs/
  7. 编辑/etc/gitlab/gitlab.rb并添加:

    1. gitaly['tls_listen_addr'] = "0.0.0.0:9999"
    2. gitaly['certificate_path'] = "/etc/gitlab/ssl/cert.pem"
    3. gitaly['key_path'] = "/etc/gitlab/ssl/key.pem"
  8. 保存文件并 .

  9. 通过观察 Gitaly 连接的类型,验证通过 TLS 提供服务的 Gitaly 通信.
  10. (可选)通过以下方式提高安全性:
    1. 通过注释或删除禁用非 TLS 连接gitaly['listen_addr']/etc/gitlab/gitlab.rb .
    2. 保存文件.
    3. .

对于源安装

  1. 为 Gitaly 服务器创建证书.
  2. 在 Gitaly 客户端上,将证书复制到系统受信任的证书中:

    1. sudo cp cert.pem /usr/local/share/ca-certificates/gitaly.crt
    2. sudo update-ca-certificates
  3. 在 Gitaly 客户端上,如下所示在/home/git/gitlab/config/gitlab.yml编辑storages

    1. gitlab:
    2. repositories:
    3. storages:
    4. default:
    5. gitaly_address: tls://gitaly1.internal:9999
    6. path: /some/dummy/path
    7. storage1:
    8. gitaly_address: tls://gitaly1.internal:9999
    9. path: /some/dummy/path
    10. storage2:
    11. gitaly_address: tls://gitaly2.internal:9999
    12. path: /some/dummy/path

    注意: /some/dummy/path应该设置为存在的本地文件夹,但是该文件夹中不会存储任何数据. 解决Gitaly 问题#1282之后,将不再需要此操作.

  4. 保存文件并 .
  5. 在 Gitaly 服务器上,创建或编辑/etc/default/gitlab并添加:

    1. export SSL_CERT_DIR=/etc/gitlab/ssl
  6. 在 Gitaly 服务器上,创建/etc/gitlab/ssl目录,然后在其中复制密钥和证书:

    1. sudo chmod 755 /etc/gitlab/ssl
    2. sudo cp key.pem cert.pem /etc/gitlab/ssl/
    3. sudo chmod 644 key.pem cert.pem
  7. 将所有 Gitaly 服务器证书(或其证书颁发机构)复制到系统受信任证书文件夹,以便 Gitaly 服务器在调用自身或其他 Gitaly 服务器时将信任该证书.

    1. sudo cp cert.pem /usr/local/share/ca-certificates/gitaly.crt
    2. sudo update-ca-certificates
  8. 编辑/home/git/gitaly/config.toml并添加:

    1. tls_listen_addr = '0.0.0.0:9999'
    2. [tls]
    3. certificate_path = '/etc/gitlab/ssl/cert.pem'
    4. key_path = '/etc/gitlab/ssl/key.pem'
  9. 保存文件并重新启动 GitLab .

  10. 通过验证通过 TLS 提供服务的 Gitaly 通信.
  11. (可选)通过以下方式提高安全性:
    1. 通过注释掉或删除/home/git/gitaly/config.toml listen_addr来禁用非 TLS 连接.
    2. 保存文件.
    3. 重新启动 GitLab .

Observe type of Gitaly connections

可以使用Prometheus观察 Gitaly 为生产环境提供服务的连接类型. 使用以下 Prometheus 查询:

  1. sum(rate(gitaly_connections_total[5m])) by (type)

gitaly-ruby

开发 Gitaly 是为了替代 GitLab 中的 Ruby 应用程序代码.

为了节省时间并避免重写现有应用程序逻辑的风险,我们选择将一些应用程序代码从 GitLab 复制到 Gitaly.

为了能够运行该代码,创建了gitaly-ruby ,它是主要 Gitaly Go 流程的” sidecar”流程. 在gitaly-ruby中实现的一些示例如下:

  • 处理 Wiki 的 RPC.
  • 代表用户创建提交的 RPC,例如合并提交.

Configure number of gitaly-ruby workers

gitaly-ruby容量比 Go 中实现的 Gitaly 少得多. 如果您的 Gitaly 服务器必须处理大量请求,则仅设置一个活动的gitaly-ruby车的默认设置可能不够.

如果您看到 Gitaly 出现ResourceExhausted错误,则很可能是您的gitaly-ruby能力不足.

您可以使用以下设置来增加 Gitaly 服务器上的gitaly-ruby进程数:

对于所有 GitLab

  1. Edit /etc/gitlab/gitlab.rb:

    1. # Default is 2 workers. The minimum is 2; 1 worker is always reserved as
    2. # a passive stand-by.
    3. gitaly['ruby_num_workers'] = 4
  2. 保存文件并 .

对于源安装

  1. Edit /home/git/gitaly/config.toml:

    1. [gitaly-ruby]
    2. num_workers = 4
  2. 保存文件并重新启动 GitLab .

Limit RPC concurrency

克隆流量可能会对您的 Gitaly 服务造成很大的压力. 大部分工作在以下任一 RPC 中完成:

  • SSHUploadPack (用于 Git SSH).
  • PostUploadPack (用于 Git HTTP).

为了防止此类工作负载使您的 Gitaly 服务器不堪重负,您可以在 Gitaly 的配置文件中设置并发限制. 例如:

  1. # in /etc/gitlab/gitlab.rb
  2. gitaly['concurrency'] = [
  3. {
  4. 'rpc' => "/gitaly.SmartHTTPService/PostUploadPack",
  5. 'max_per_repo' => 20
  6. },
  7. {
  8. 'rpc' => "/gitaly.SSHService/SSHUploadPack",
  9. 'max_per_repo' => 20
  10. }
  11. ]

这限制了给定 RPC 正在进行的 RPC 调用的数量. 该限制适用于每个存储库. 在上面的示例中:

  • Gitaly 服务器提供服务的每个存储库最多可以同时PostUploadPack 20 个PostUploadPack RPC 调用,而SSHUploadPack则相同.
  • 如果另一个请求进入了已用完其 20 个插槽的存储库,则该请求将排队.

您可以使用 Gitaly 日志和 Prometheus 观察此队列的行为:

  • 在 Gitaly 日志中,查找字符串(或结构化日志字段) acquire_ms . 具有此字段的消息正在报告有关并发限制器的信息.
  • 在 Prometheus 中,查找以下指标:

    • gitaly_rate_limiting_in_progress.
    • gitaly_rate_limiting_queued.
    • .

注意:尽管 Prometheus 度量标准的名称包含rate_limiting ,但它是并发限制器,而不是速率限制器. 如果 Gitaly 客户端非常快地连续发出 1000 个请求,则并发不会超过 1,并且并发限制器无效.

在生产环境中轮换凭证通常需要停机,导致停机或两者兼而有之.

但是,您可以旋转 Gitaly 凭据而不会中断服务. 旋转 Gitaly 身份验证令牌涉及:

如果您在单个服务器上运行 GitLab,则此过程也适用. 在这种情况下,” Gitaly 服务器”和” Gitaly 客户端”是指同一台计算机.

Verify authentication monitoring

旋转 Gitaly 身份验证令牌之前,请验证您可以使用 Prometheus 监视 GitLab 安装的身份验证行为. 使用以下 Prometheus 查询:

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

可能还存在速率为 0 的其他数字.我们只关心非零数字.

唯一的非零数字应具有enforced="true",status="ok" . 如果您还有其他非零数字,则说明您的配置有问题.

status="ok"数字反映您当前的请求率. 在上面的示例中,Gitaly 每秒处理大约 4000 个请求.

既然您已经确定可以监视 GitLab 安装的 Gitaly 身份验证行为,则可以开始其余过程.

通过将 Gitaly 服务器置于”身份验证过渡”模式,从而暂时禁用 Gitaly 服务器上的 Gitaly 身份验证,如下所示:

  1. # in /etc/gitlab/gitlab.rb
  2. gitaly['auth_transitioning'] = true

进行此更改后,您的应返回如下内容:

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

因为enforced="false" ,所以可以安全地开始部署新令牌.

Update Gitaly authentication token

要在每个 Gitaly 客户端 Gitaly 服务器上更新为新的 Gitaly 身份验证令牌,请执行以下操作:

  1. 更新配置:

    1. # in /etc/gitlab/gitlab.rb
    2. gitaly['auth_token'] = '<new secret token>'
  2. 重新启动 Gitaly:

    1. gitlab-ctl restart gitaly

如果在实施此更改的同时运行 ,您将看到被enforced="false",status="denied"计数器的非零值.

Ensure there are no authentication failures

设置新令牌并重新启动所有涉及的服务之后,您将的组合:

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

在所有 Gitaly 客户端和 Gitaly 服务器获取了新令牌之后,应enforced="false",status="would be ok" 唯一的非零费率 enforced="false",status="would be ok" .

Disable “auth transitioning” mode

要重新启用 Gitaly 身份验证,请禁用”身份验证转换”模式. 如下更新您的 Gitaly 服务器上的配置:

  1. # in /etc/gitlab/gitlab.rb
  2. gitaly['auth_transitioning'] = false

警告:如果不完成此步骤,则没有 Gitaly 身份验证 .

Verify authentication is enforced

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

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

请注意, enforced="true"表示正在执行身份验证.

Direct Git access bypassing Gitaly

虽然可以使用 Git 客户端直接访问磁盘上存储的 Gitaly 存储库,但由于不断改进和更改 Gitaly,因此不建议这样做. 这些改进可能会使假设无效,从而导致性能下降,不稳定甚至数据丢失.

Gitaly 进行了优化,例如info/refs广告缓存 ,它依赖于 Gitaly 通过官方 gRPC 接口控制和监视对存储库的访问. 同样,Praefect 具有优化功能,例如容错和分布式读取,这些优化取决于 gRPC 接口和数据库来确定存储库状态.

由于这些原因, 直接访问存储库需要您自担风险,并且不受支持 .

Direct access to Git in GitLab

直接访问 Git 使用 GitLab 中称为” Rugged patch”的代码.

History

在 Gitaly 存在之前,现在 Gitaly 客户端用来直接访问 Git 存储库的是:

  • 如果是单机 Omnibus GitLab 安装,则在本地磁盘上
  • 如果是水平缩放的 GitLab 安装,请使用 NFS.

除了运行简单的git命令之外,GitLab 还使用了一个名为的 Ruby 库. Rugged 是围绕libgit2的包装, 是 C 库形式的 Git 的独立实现.

随着时间的流逝,很明显 Rugged(特别是与Unicorn结合使用)非常有效. 因为libgit2是一个库而不是一个外部进程,所以之间的开销很小:

  • GitLab 应用程序代码试图在 Git 存储库中查找数据.
  • Git 实现本身.

由于 Rugged 和 Unicorn 的组合是如此有效,因此 GitLab 的应用程序代码最终会进行大量重复的 Git 对象查找. 例如,查找master在一个请求中提交了十几次. 我们可以编写效率低下的代码而不会降低性能.

当我们将这些 Git 查找迁移到 Gitaly 调用时,我们突然发现每个 Git 查找的固定成本要高得多. 即使 Gitaly 能够重新使用已经在运行的git进程(例如,查找提交),您仍然可以:

  • 往返于 Gitaly 的网络费用.
  • 在 Gitaly 中,是将 Gitaly 连接到git进程的 Unix 管道上的写入/读取往返.

使用 GitLab.com 进行测量,我们减少了每个请求的 Gitaly 呼叫次数,直到不再感觉到 Rugged 效率的下降. 这也有助于我们直接在 Git 文件服务器上运行 Gitaly 本身,而不是通过 NFS 挂载. 这给了我们提速,抵消了不再使用 Rugged 带来的负面影响.

不幸的是,GitLab 的其他部署无法像我们在 GitLab.com 上那样删除 NFS,这两个方面都是最糟糕的:

  • NFS 的速度较慢.
  • The increased inherent overhead of Gitaly.

在 Gitaly 迁移项目期间从 GitLab 中删除的代码影响了这些部署. 作为这些基于 NFS 的部署的性能变通办法,我们重新引入了一些旧的 Rugged 代码. 重新引入的代码被非正式地称为” Rugged patch”.

How it works

执行直接 Git 访问的 Ruby 方法位于功能标志的后面,默认情况下处于禁用状态. 设置功能标记以获得最佳性能并不方便,因此我们添加了一种自动机制,可以直接访问 Git.

当 GitLab 调用具有”加固补丁”的函数时,它将执行两项检查:

  • 数据库中是否设置了此补丁程序的功能标志? 如果是这样,功能标记设置将控制 GitLab 对”坚固补丁”代码的使用.
  • 如果未设置功能标志,则 GitLab 尝试直接访问 Gitaly 服务器下方的文件系统. 如果可以,它将使用” Rugged patch”.

这两个检查的结果都被缓存.

为了查看 GitLab 是否可以直接访问存储库文件系统,我们使用以下启发式:

  • Gitaly 确保文件系统在其根目录中具有一个带有 UUID 的元数据文件.
  • Gitaly 通过ServerInfo RPC 将此 UUID 报告给 GitLab.
  • GitLab Rails 尝试直接读取元数据文件. 如果存在,并且 UUID 匹配,则假定我们具有直接访问权限.

默认情况下,在 Omnibus GitLab 中启用直接 Git 访问,因为它会在 GitLab 配置文件config/gitlab.yml填写正确的存储库路径. 这满足了 UUID 检查.

Transition to Gitaly Cluster

为了消除复杂性,我们必须删除 GitLab 中的直接 Git 访问. 但是,只要某些 GitLab 安装需要 NFS 上的 Git 存储库,我们就无法删除它.

我们在 GitLab 中删除直接 Git 访问的工作有两个方面:

  • 减少 GitLab 进行的低效率 Gitaly 查询的数量.
  • 说服容错或水平扩展的 GitLab 实例的管理员从 NFS 迁移.

第二个方面是唯一真正的解决方案. 为此,我们开发了Gitaly Cluster .

Checking versions when using standalone Gitaly servers

使用独立的 Gitaly 服务器时,必须确保它们与 GitLab 的版本相同,以确保完全兼容. 检查您的 GitLab 实例上的管理区域> Gitaly 服务器 ,并确认所有 Gitaly 服务器都是Up to date .

Gitaly standalone software versions diagram

gitaly-debug命令提供用于” Gitaly”和” Git”性能的”生产调试”工具. 它旨在帮助生产工程师和支持工程师调查 Gitaly 性能问题.

如果您使用的是 GitLab 11.6 或更高版本,则此工具应已安装在您的 GitLab / Gitaly 服务器上,位于/opt/gitlab/embedded/bin/gitaly-debug . 如果要研究旧版本的 GitLab,可以离线编译此工具,然后将可执行文件复制到服务器:

  1. git clone https://gitlab.com/gitlab-org/gitaly.git
  2. cd cmd/gitaly-debug
  3. GOOS=linux GOARCH=amd64 go build -o gitaly-debug

要查看gitaly-debug的帮助页面以gitaly-debug受支持的子命令列表,请运行:

  1. gitaly-debug -h

Commits, pushes, and clones return a 401

  1. remote: GitLab: 401 Unauthorized

您将需要将gitlab-secrets.json文件与 Gitaly 客户端(GitLab 应用程序节点)同步.

Client side gRPC logs

Gitaly 使用 RPC 框架. Ruby gRPC 客户端具有自己的日志文件,当您看到 Gitaly 错误时,该文件可能包含有用的信息. 您可以使用GRPC_LOG_LEVEL环境变量控制 gRPC 客户端的日志级别. 默认级别为WARN .

您可以使用以下命令运行 gRPC 跟踪:

  1. sudo GRPC_TRACE=all GRPC_VERBOSITY=DEBUG gitlab-rake gitlab:gitaly:check

Observing gitaly-ruby traffic

gitaly-ruby的内部实现细节,因此,对gitaly-ruby流程内部发生的情况gitaly-ruby .

如果已设置 Prometheus 来抓取 Gitaly 进程,则可以通过查询grpc_client_handled_totalgrpc_client_handled_total gitaly-ruby各个 RPC 的请求率和错误代码. 严格来说,此度量标准并未区分gitaly-ruby和其他 RPC,但实际上(自 GitLab 11.9 起),Gitaly 本身进行的所有 gRPC 调用都是从 Gitaly 主过程到其gitaly-ruby边车之一的内部调用.

假设您的grpc_client_handled_total计数器仅观察到 Gitaly,以下查询将显示 RPC 在内部(最有可能)实现为对gitaly-ruby调用:

  1. sum(rate(grpc_client_handled_total[5m])) by (grpc_method) > 0

Repository changes fail with a 401 Unauthorized error

如果您在自己的服务器上运行 Gitaly,并注意到用户可以成功克隆和获取存储库(通过 SSH 和 HTTPS),但是在未获得401 Unauthorized情况下,无法推送到它们或在 Web UI 中对存储库进行更改消息,那么 Gitaly 可能由于拥有错误的 secrets 文件而无法通过 Gitaly 客户端进行身份验证.

确认以下所有内容均正确:

  • When any user performs a git push to any repository on this Gitaly server, it fails with the following error (note the 401 Unauthorized):

    1. remote: GitLab: 401 Unauthorized
    2. To <REMOTE_URL>
    3. ! [remote rejected] branch-name -> branch-name (pre-receive hook declined)
    4. error: failed to push some refs to '<REMOTE_URL>'
  • 当任何用户使用 GitLab UI 从存储库添加或修改文件时,该文件都会立即失败,并显示红色401 Unauthorized横幅.

  • 创建一个新项目并成功创建该项目,但不会创建 README.
  • 将日志尾随在 Gitaly 客户端上并重现该错误时,到达/api/v4/internal/allowed端点时会出现401错误:

    1. # api_json.log
    2. {
    3. "time": "2019-07-18T00:30:14.967Z",
    4. "severity": "INFO",
    5. "duration": 0.57,
    6. "db": 0,
    7. "view": 0.57,
    8. "status": 401,
    9. "method": "POST",
    10. "path": "\/api\/v4\/internal\/allowed",
    11. "params": [
    12. {
    13. "key": "action",
    14. "value": "git-receive-pack"
    15. },
    16. {
    17. "key": "changes",
    18. "value": "REDACTED"
    19. },
    20. {
    21. "key": "gl_repository",
    22. "value": "REDACTED"
    23. },
    24. {
    25. "key": "project",
    26. "value": "\/path\/to\/project.git"
    27. },
    28. {
    29. "key": "protocol",
    30. "value": "web"
    31. },
    32. {
    33. "key": "env",
    34. "value": "{\"GIT_ALTERNATE_OBJECT_DIRECTORIES\":[],\"GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE\":[],\"GIT_OBJECT_DIRECTORY\":null,\"GIT_OBJECT_DIRECTORY_RELATIVE\":null}"
    35. },
    36. {
    37. "key": "user_id",
    38. "value": "2"
    39. },
    40. {
    41. "key": "secret_token",
    42. "value": "[FILTERED]"
    43. }
    44. ],
    45. "host": "gitlab.example.com",
    46. "ip": "REDACTED",
    47. "ua": "Ruby",
    48. "route": "\/api\/:version\/internal\/allowed",
    49. "queue_duration": 4.24,
    50. "gitaly_calls": 0,
    51. "gitaly_duration": 0,
    52. "correlation_id": "XPUZqTukaP3"
    53. }
    54. # nginx_access.log
    55. [IP] - - [18/Jul/2019:00:30:14 +0000] "POST /api/v4/internal/allowed HTTP/1.1" 401 30 "" "Ruby"

要解决此问题,请确认 Gitaly 服务器上的 gitlab 与 Gitaly 客户端上的文件匹配. 如果不匹配,请更新 Gitaly 服务器上的密码文件以匹配 Gitaly 客户端,然后 .

Command line tools cannot connect to Gitaly

如果使用命令行(CLI)工具连接到 Gitaly 服务器时遇到问题,并且某些操作导致出现14: Connect Failed错误消息,则意味着 gRPC 无法访问您的 Gitaly 服务器.

确认您可以通过 TCP 到达 Gitaly:

  1. sudo gitlab-rake gitlab:tcp_check[GITALY_SERVER_IP,GITALY_LISTEN_PORT]

如果 TCP 连接失败,请检查您的网络设置和防火墙规则. 如果 TCP 连接成功,则您的网络和防火墙规则正确.

如果您在命令行环境(例如 Bash)中使用代理服务器,则这些代理服务器可能会干扰您的 gRPC 通信.

如果使用 Bash 或兼容的命令行环境,请运行以下命令来确定是否配置了代理服务器:

  1. echo $http_proxy
  2. echo $https_proxy

如果这些变量中的任何一个都有值,则您的 Gitaly CLI 连接可能正在通过无法连接到 Gitaly 的代理进行路由.

要删除代理设置,请运行以下命令(取决于哪些变量具有值):

  1. unset http_proxy

Gitaly not listening on new address after reconfiguring

当更新gitaly['listen_addr']gitaly['prometheus_listen_addr']值时,Gitaly 可能会在sudo gitlab-ctl reconfigure后继续侦听旧地址.

发生这种情况时,执行sudo gitlab-ctl restart将解决此问题. 解决此问题后,将不再需要 .

Permission denied errors appearing in Gitaly logs when accessing repositories from a standalone Gitaly server

如果即使文件权限正确也发生此错误,则 Gitaly 服务器可能正在发生 .

请确保 Gitaly 客户端和服务器已同步,并在可能的情况下使用 NTP 时间服务器保持同步.

Praefect