Gitaly 故障排除
- Tier: Free, Premium, Ultimate
- Offering: GitLab Self-Managed
以下部分提供了 Gitaly 错误的可能解决方案。
另请参阅 Gitaly 超时设置,
以及我们关于解析 gitaly/current 文件的建议。
使用独立 Gitaly 服务器时检查版本
使用独立 Gitaly 服务器时,必须确保它们与 GitLab 版本相同, 以保证完全兼容性:
- 在左侧边栏底部,选择 管理员。
- 选择 概览 > Gitaly 服务器。
- 确认所有 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 包安装中设置此功能:
-
将以下内容添加到您的
gitlab.rb文件中:gitaly['env'] = { "GODEBUG=http2debug" => "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 Unauthorized 和 JWT::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 check 因 401 状态码而失败
如果 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 completeGitaly 必须能够连接到自身才能完成某些操作。如果 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 文件夹中,
并:
- 重新配置 GitLab 以便证书被符号链接
- 手动重启 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 运行时目录:
- 将
gitaly['runtime_dir'] = '<PATH_WITH_EXEC_PERM>'添加到/etc/gitlab/gitlab.rb并指定未设置noexec的位置。 - 运行
sudo gitlab-ctl reconfigure。
提交签名因 invalid argument 或 invalid data 而失败
如果提交签名因以下任一错误而失败:
invalid argument: signing key is encryptedinvalid 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 正在拒绝执行,请考虑以下事项:
-
在您的
fapolicyd配置中允许/var/opt/gitlab/gitaly中的所有可执行文件:allow perm=any all : ftype=application/x-executable dir=/var/opt/gitlab/gitaly/ -
重启服务:
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 二进制文件执行的规则:
-
在
/etc/fapolicyd/rules.d/89-gitlab.rules创建一个文件。 -
在文件中输入以下内容:
allow perm=any all : ftype=application/x-executable dir=/var/opt/gitlab/gitaly/ -
重启服务:
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