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

Gitaly 故障排除

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

以下部分提供了 Gitaly 错误的可能解决方案。

另请参阅 Gitaly 超时设置, 以及我们关于解析 gitaly/current 文件的建议。

使用独立 Gitaly 服务器时检查版本

使用独立 Gitaly 服务器时,必须确保它们与 GitLab 版本相同, 以保证完全兼容性:

  1. 在左侧边栏底部,选择 管理员
  2. 选择 概览 > Gitaly 服务器
  3. 确认所有 Gitaly 服务器都显示为最新版本。

查找存储资源详细信息

您可以在 Rails 控制台中运行以下命令, 以确定 Gitaly 存储上的可用空间和已用空间:

Gitlab::GitalyClient::ServerService.new("default").storage_disk_statistics
# 对于 Gitaly 集群 (Praefect)
Gitlab::GitalyClient::ServerService.new("<storage name>").disk_statistics

使用 gitaly-debug

gitaly-debug 命令为 Gitaly 和 Git 性能提供"生产调试"工具。它旨在帮助生产工程师和支持工程师调查 Gitaly 性能问题。

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

gitaly-debug -h

在故障排除需要 Git 时使用 gitaly git

使用 gitaly git 通过与 Gitaly 相同的 Git 执行环境执行 Git 命令,用于调试或测试目的。gitaly git 是确保版本兼容性的首选方法。

gitaly git 将所有参数传递给底层的 Git 调用, 并支持 Git 支持的所有形式的输入。要使用 gitaly git,请运行:

sudo -u git -- /opt/gitlab/embedded/bin/gitaly git <git-command>

例如,要在 Linux 包实例的仓库工作目录中通过 Gitaly 运行 git ls-tree

sudo -u git -- /opt/gitlab/embedded/bin/gitaly git ls-tree --name-status HEAD

提交、推送和克隆返回 401

remote: GitLab: 401 Unauthorized

您需要将 gitlab-secrets.json 文件与您的 GitLab 应用程序节点同步。

仓库页面上的 500 和 fetching folder content 错误

Fetching folder content(获取文件夹内容)以及在某些情况下的 500 错误, 表示 GitLab 和 Gitaly 之间存在连接问题。 请查阅客户端 gRPC 日志 以获取详细信息。

客户端 gRPC 日志

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

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

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

如果此命令因 failed to connect to all addresses 错误而失败, 请检查 SSL 或 TLS 问题:

/opt/gitlab/embedded/bin/openssl s_client -connect <gitaly-ipaddress>:<port> -verify_return_error

检查 Verify return code 字段是否指示 已知的 Linux 包安装配置问题

如果 openssl 成功但 gitlab-rake gitlab:gitaly:check 失败, 请检查 Gitaly 的证书要求

服务器端 gRPC 日志

gRPC 跟踪也可以通过 GODEBUG=http2debug 环境变量在 Gitaly 本身中启用。要在 Linux 包安装中设置此功能:

  1. 将以下内容添加到您的 gitlab.rb 文件中:

    gitaly['env'] = {
      "GODEBUG=http2debug" => "2"
    }
  2. 重新配置 GitLab。

将 Git 进程与 RPC 关联

有时您需要找出是哪个 Gitaly RPC 创建了特定的 Git 进程。

一种方法是使用 DEBUG 日志记录。但是,这需要提前启用, 并且生成的日志非常冗长。

一种轻量级的关联方法是通过检查 Git 进程的环境 (使用其 PID)并查看 CORRELATION_ID 变量:

PID=<Git process ID>
sudo cat /proc/$PID/environ | tr '\0' '\n' | grep ^CORRELATION_ID=

对于 git cat-file 进程,此方法不可靠,因为 Gitaly 内部在 RPC 之间池化和重用这些进程。

仓库更改因 401 Unauthorized 错误而失败

如果您在自己的服务器上运行 Gitaly 并注意到以下情况:

  • 用户可以通过 SSH 和 HTTPS 成功克隆和获取仓库。
  • 用户无法推送到仓库,或在尝试在 Web UI 中更改仓库时收到 401 Unauthorized 消息。

Gitaly 可能无法通过 Gitaly 客户端进行身份验证,因为它具有 错误的密钥文件

确认以下情况均为真:

  • 当任何用户对此 Gitaly 服务器上的任何仓库执行 git push 时,它因 401 Unauthorized 错误而失败:

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

  • 创建新项目并使用 README 初始化成功创建了项目,但没有创建 README。

  • 当在 Gitaly 客户端上跟踪日志并重现错误时,在访问 /api/v4/internal/allowed 端点时会出现 401 错误:

    # api_json.log
    {
      "time": "2019-07-18T00:30:14.967Z",
      "severity": "INFO",
      "duration": 0.57,
      "db": 0,
      "view": 0.57,
      "status": 401,
      "method": "POST",
      "path": "\/api\/v4\/internal\/allowed",
      "params": [
        {
          "key": "action",
          "value": "git-receive-pack"
        },
        {
          "key": "changes",
          "value": "REDACTED"
        },
        {
          "key": "gl_repository",
          "value": "REDACTED"
        },
        {
          "key": "project",
          "value": "\/path\/to\/project.git"
        },
        {
          "key": "protocol",
          "value": "web"
        },
        {
          "key": "env",
          "value": "{\"GIT_ALTERNATE_OBJECT_DIRECTORIES\":[],\"GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE\":[],\"GIT_OBJECT_DIRECTORY\":null,\"GIT_OBJECT_DIRECTORY_RELATIVE\":null}"
        },
        {
          "key": "user_id",
          "value": "2"
        },
        {
          "key": "secret_token",
          "value": "[FILTERED]"
        }
      ],
      "host": "gitlab.example.com",
      "ip": "REDACTED",
      "ua": "Ruby",
      "route": "\/api\/:version\/internal\/allowed",
      "queue_duration": 4.24,
      "gitaly_calls": 0,
      "gitaly_duration": 0,
      "correlation_id": "XPUZqTukaP3"
    }
    
    # nginx_access.log
    [IP] - - [18/Jul/2019:00:30:14 +0000] "POST /api/v4/internal/allowed HTTP/1.1" 401 30 "" "Ruby"

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

如果您已确认所有 Gitaly 服务器和客户端上的 gitlab-secrets.json 文件相同, 应用程序可能正在从不同的文件获取此密钥。Gitaly 服务器的 config.toml file 指示正在使用的密钥文件。

仓库推送因 401 UnauthorizedJWT::VerificationError 而失败

尝试 git push 时,您可能会看到:

  • 401 Unauthorized 错误。

  • 服务器日志中的以下内容:

    {
      ...
      "exception.class":"JWT::VerificationError",
      "exception.message":"Signature verification raised",
      ...
    }

当 GitLab 服务器已升级到 GitLab 15.5 或更高版本但 Gitaly 尚未升级时,会出现这种错误组合。

从 GitLab 15.5 开始,GitLab 使用 JWT 令牌而不是共享密钥与 GitLab Shell 进行身份验证。 您应该遵循升级外部 Gitaly 的建议并在 GitLab 服务器之前升级 Gitaly。

仓库推送因 deny updating a hidden ref 错误而失败

Gitaly 具有只读的内部 GitLab 引用,用户不允许更新。如果您尝试使用 git push --mirror 更新内部引用,Git 会返回拒绝错误 deny updating a hidden ref

以下引用是只读的:

  • refs/environments/
  • refs/keep-around/
  • refs/merge-requests/
  • refs/pipelines/

要仅镜像推送分支和标签,并避免尝试镜像推送受保护的引用,请运行:

git push --force-with-lease origin 'refs/heads/*:refs/heads/*' 'refs/tags/*:refs/tags/*'

管理员想要推送的任何其他命名空间也可以通过 额外的 refspecs 包含在其中。

命令行工具无法连接到 Gitaly

如果出现以下情况,gRPC 无法访问您的 Gitaly 服务器:

  • 您无法使用命令行工具连接到 Gitaly 服务器。
  • 某些操作导致出现 14: Connect Failed 错误消息。

验证您可以通过 TCP 访问 Gitaly:

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

如果 TCP 连接:

  • 失败,请检查您的网络设置和防火墙规则。
  • 成功,则您的网络和防火墙规则是正确的。

如果您在命令行环境(如 Bash)中使用代理服务器,这些可能会干扰您的 gRPC 流量。

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

echo $http_proxy
echo $https_proxy

如果这些变量中的任何一个有值,您的 Gitaly CLI 连接可能会被路由到无法连接到 Gitaly 的代理。

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

unset http_proxy
unset https_proxy

访问仓库时 Gitaly 或 Praefect 日志中出现权限被拒绝错误

您可能会在 Gitaly 和 Praefect 日志中看到以下内容:

{
  ...
  "error":"rpc error: code = PermissionDenied desc = permission denied: token has expired",
  "grpc.code":"PermissionDenied",
  "grpc.meta.client_name":"gitlab-web",
  "grpc.request.fullMethod":"/gitaly.ServerService/ServerInfo",
  "level":"warning",
  "msg":"finished unary call with code PermissionDenied",
  ...
}

日志中的这些信息是 gRPC 调用的 错误响应代码

如果发生此错误,即使 Gitaly 身份验证令牌已正确设置, 很可能是 Gitaly 服务器正在经历 时钟漂移。发送到 Gitaly 的身份验证令牌包含时间戳。为了被视为有效,Gitaly 要求该时间戳在 Gitaly 服务器时间的 60 秒内。

确保 Gitaly 客户端和服务器已同步,并使用网络时间协议 (NTP) 时间 服务器来保持它们同步。

重新配置后 Gitaly 未在新地址上监听

更新 gitaly['configuration'][:listen_addr]gitaly['configuration'][:prometheus_listen_addr] 值时,在 sudo gitlab-ctl reconfigure 之后,Gitaly 可能会继续在旧地址上监听。

发生这种情况时,请运行 sudo gitlab-ctl restart 来解决问题。由于此问题已解决,这应该不再是必要的。

健康检查警告

/var/log/gitlab/praefect/current 中的以下警告可以忽略。

"error":"full method name not found: /grpc.health.v1.Health/Check",
"msg":"error when looking up method info"

文件未找到错误

/var/log/gitlab/gitaly/current 中的以下错误可以忽略。 它们是由 GitLab Rails 应用程序检查仓库中不存在的特定文件引起的。

"error":"not found: .gitlab/route-map.yml"
"error":"not found: Dockerfile"
"error":"not found: .gitlab-ci.yml"

启用 Dynatrace 时 Git 推送缓慢

Dynatrace 可能会导致 sudo -u git -- /opt/gitlab/embedded/bin/gitaly-hooks 引用事务钩子, 在启动和关闭时花费几秒钟时间。用户推送时 gitaly-hooks 会执行两次,这会导致显著的延迟。

如果启用 Dynatrace 时 Git 推送太慢,请禁用 Dynatrace。

gitaly check401 状态码而失败

如果 Gitaly 无法访问内部 GitLab API,gitaly check 可能会因 401 状态码而失败。

解决此问题的一种方法是确保在 gitlab.rb 中使用 gitlab_rails['internal_api_url'] 配置的 GitLab 内部 API URL 的条目是正确的。

使用 Gitaly TLS 时新合并请求的更改(差异)不加载

启用带 TLS 的 Gitaly后,不会生成新合并请求的更改(差异), 您在 GitLab 中看到以下消息:

Building your merge request... This page will update when the build is complete

Gitaly 必须能够连接到自身才能完成某些操作。如果 Gitaly 证书不受 Gitaly 服务器信任, 则无法生成合并请求差异。

如果 Gitaly 无法连接到自身,您会在 Gitaly 日志中看到类似以下消息:

{
   "level":"warning",
   "msg":"[core] [Channel #16 SubChannel #17] grpc: addrConn.createTransport failed to connect to {Addr: \"ext-gitaly.example.com:9999\", ServerName: \"ext-gitaly.example.com:9999\", }. Err: connection error: desc = \"transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate signed by unknown authority\"",
   "pid":820,
   "system":"system",
   "time":"2023-11-06T05:40:04.169Z"
}
{
   "level":"info",
   "msg":"[core] [Server #3] grpc: Server.Serve failed to create ServerTransport: connection error: desc = \"ServerHandshake(\\"x.x.x.x:x\\") failed: wrapped server handshake: remote error: tls: bad certificate\"",
   "pid":820,
   "system":"system",
   "time":"2023-11-06T05:40:04.169Z"
}

要解决此问题,请确保您已将 Gitaly 证书添加到 Gitaly 服务器上的 /etc/gitlab/trusted-certs 文件夹中, 并:

  1. 重新配置 GitLab 以便证书被符号链接
  2. 手动重启 Gitaly sudo gitlab-ctl restart gitaly 以便 Gitaly 进程加载证书。

Gitaly 无法在存储于 noexec 文件系统上的进程中派生

noexec 选项应用于挂载点(例如 /var)会导致 Gitaly 抛出与派生进程相关的 permission denied 错误。例如:

fork/exec /var/opt/gitlab/gitaly/run/gitaly-2057/gitaly-git2go: permission denied

要解决此问题,请从文件系统挂载中删除 noexec 选项。另一种方法是更改 Gitaly 运行时目录:

  1. gitaly['runtime_dir'] = '<PATH_WITH_EXEC_PERM>' 添加到 /etc/gitlab/gitlab.rb 并指定未设置 noexec 的位置。
  2. 运行 sudo gitlab-ctl reconfigure

提交签名因 invalid argumentinvalid data 而失败

如果提交签名因以下任一错误而失败:

  • invalid argument: signing key is encrypted
  • invalid data: tag byte does not have MSB set

发生此错误是因为 Gitaly 提交签名是无头的,不与特定用户关联。GPG 签名密钥必须在没有密码短语的情况下创建,或者在导出之前必须删除密码短语。

Gitaly 日志在 info 消息中显示错误

由于 GitLab 16.3 中引入的错误,额外的条目被写入到 Gitaly 日志。这些日志条目包含 "level":"info",但 msg 字符串似乎包含错误。

例如:

{"level":"info","msg":"[core] [Server #3] grpc: Server.Serve failed to create ServerTransport: connection error: desc = \"ServerHandshake(\\"x.x.x.x:x\\") failed: wrapped server handshake: EOF\"","pid":6145,"system":"system","time":"2023-12-14T21:20:39.999Z"}

此日志条目的原因是底层的 gRPC 库有时会输出详细的传输日志。这些日志条目看起来像是错误,但通常可以安全地忽略。

此错误已在 GitLab 16.4.5、16.5.5 和 16.6.0 中修复,这可以防止此类消息 被写入 Gitaly 日志。

分析 Gitaly

Gitaly 在 Prometheus 监听端口上公开了几个 Go 内置性能分析工具。例如,如果 Prometheus 在 GitLab 服务器的端口 9236 上监听:

  • 获取正在运行的 goroutines 列表及其回溯:

    curl --output goroutines.txt "http://<gitaly_server>:9236/debug/pprof/goroutine?debug=2"
  • 运行 30 秒的 CPU 分析:

    curl --output cpu.bin "http://<gitaly_server>:9236/debug/pprof/profile"
  • 分析堆内存使用情况:

    curl --output heap.bin "http://<gitaly_server>:9236/debug/pprof/heap"
  • 记录 5 秒的执行跟踪。这会影响运行时的 Gitaly 性能:

    curl --output trace.bin "http://<gitaly_server>:9236/debug/pprof/trace?seconds=5"

在安装了 go 的主机上,可以在浏览器中查看 CPU 分析和堆分析:

go tool pprof -http=:8001 cpu.bin
go tool pprof -http=:8001 heap.bin

可以通过运行以下命令查看执行跟踪:

go tool trace heap.bin

分析 Git 操作

在 GitLab Self-Managed 上,默认情况下此功能不可用。要使其可用,管理员可以启用功能标志 名为 log_git_traces。在 GitLab.com 上,此功能可用,但只能由 GitLab.com 管理员配置。在 GitLab Dedicated 上,此功能不可用。

您可以通过将有关 Git 操作的额外信息发送到 Gitaly 日志来分析 Gitaly 执行的 Git 操作。有了这些信息,用户可以更深入地了解 性能优化、调试和一般遥测收集。有关更多信息,请参阅 Git Trace2 API 参考

为防止系统过载,额外信息记录受到速率限制。如果超过速率限制,则跳过跟踪。但是,当速率返回到健康状态时, 跟踪会自动再次处理。速率限制确保系统保持稳定,并避免因过度跟踪处理而产生任何不利影响。

GitLab 恢复后仓库显示为空

使用 fapolicyd 增强安全性时,GitLab 可能报告从 GitLab 备份文件恢复成功,但是:

  • 仓库显示为空。

  • 创建新文件会导致类似以下的错误:

    13:commit: commit: starting process [/var/opt/gitlab/gitaly/run/gitaly-5428/gitaly-git2go -log-format json -log-level -correlation-id
    01GP1383JV6JD6MQJBH2E1RT03 -enabled-feature-flags -disabled-feature-flags commit]: fork/exec /var/opt/gitlab/gitaly/run/gitaly-5428/gitaly-git2go: operation not permitted.
  • Gitaly 日志可能包含类似以下的错误:

     "error": "exit status 128, stderr: \"fatal: cannot exec '/var/opt/gitlab/gitaly/run/gitaly-5428/hooks-1277154941.d/reference-transaction':
    
      Operation not permitted\nfatal: cannot exec '/var/opt/gitlab/gitaly/run/gitaly-5428/hooks-1277154941.d/reference-transaction': Operation
      not permitted\nfatal: ref updates aborted by hook\n\"",
     "grpc.code": "Internal",
     "grpc.meta.deadline_type": "none",
     "grpc.meta.method_type": "client_stream",
     "grpc.method": "FetchBundle",
     "grpc.request.fullMethod": "/gitaly.RepositoryService/FetchBundle",
    ...

您可以使用 调试模式 来帮助确定 fapolicyd 是否基于当前规则拒绝执行。

如果您发现 fapolicyd 正在拒绝执行,请考虑以下事项:

  1. 在您的 fapolicyd 配置中允许 /var/opt/gitlab/gitaly 中的所有可执行文件:

    allow perm=any all : ftype=application/x-executable dir=/var/opt/gitlab/gitaly/
  2. 重启服务:

    sudo systemctl restart fapolicyd
    
    sudo gitlab-ctl restart gitaly

推送到启用 fapolicyd 的 RHEL 实例时出现 Pre-receive hook declined 错误

推送到启用 fapolicyd 的基于 RHEL 的实例时,您可能会收到 Pre-receive hook declined 错误。发生此错误是因为 fapolicyd 可能会阻止 Gitaly 二进制文件的执行。要解决此问题,请执行以下任一操作:

  • 禁用 fapolicyd
  • 创建 fapolicyd 规则以在启用 fapolicyd 的情况下允许执行 Gitaly 二进制文件。

要创建允许 Gitaly 二进制文件执行的规则:

  1. /etc/fapolicyd/rules.d/89-gitlab.rules 创建一个文件。

  2. 在文件中输入以下内容:

    allow perm=any all : ftype=application/x-executable dir=/var/opt/gitlab/gitaly/
  3. 重启服务:

    systemctl restart fapolicyd

守护进程重启后,新规则生效。

删除具有重复路径的存储后更新仓库

在 GitLab 17.0 中,对配置具有重复路径的存储的支持已被移除。这可能意味着您 必须从 gitaly 配置中删除重复的存储配置。

仅当新旧存储在同一 Gitaly 服务器上共享相同的磁盘路径时,才使用此 Rake 任务。在任何其他情况下使用此 Rake 任务 会导致仓库不可用。在所有其他情况下,使用项目仓库存储移动 API 在存储之间传输项目。

当从 Gitaly 配置中删除使用与另一个存储相同路径的存储时, 与旧存储关联的项目必须重新分配给新存储。

例如,您可能有类似以下的配置:

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

如果您要从配置中删除 duplicate-path,您将运行以下 Rake 任务,将分配给它的任何项目改为关联到 default

sudo gitlab-rake "gitlab:gitaly:update_removed_storage_projects[duplicate-path, default]"
sudo -u git -H bundle exec rake "gitlab:gitaly:update_removed_storage_projects[duplicate-path, default]" RAILS_ENV=production