本文适用于 GitLab Free、Premium、Ultimate,以及 GitLab.com、GitLab Self-Managed 和 GitLab Dedicated,汇集 GitLab Runner 常见问题及排查方法。
通用排查方法
查看日志
GitLab Runner 服务向 syslog 写入日志,具体查看方式可参考发行版文档。如果系统提供 journalctl,可以使用以下命令;示例也列出了 Docker 与 Kubernetes 环境的日志命令:
journalctl --unit=gitlab-runner.service -n 100 --no-pager
docker logs gitlab-runner-container # Docker
kubectl logs gitlab-runner-pod # Kubernetes
重启服务
systemctl restart gitlab-runner.service
查看 Docker Machine 实例
sudo docker-machine ls
sudo su - && docker-machine ls
删除所有 Docker Machine 实例
以下是原文提供的删除命令,会移除所列机器:
docker-machine rm $(docker-machine ls -q)
应用 config.toml 修改
systemctl restart gitlab-runner.service
docker-machine rm $(docker-machine ls -q) # Docker machine
journalctl --unit=gitlab-runner.service -f # Tail the logs to check for potential errors
确认 GitLab 与 Runner 版本
GitLab 力求保持向后兼容,但排查问题的第一步,仍应确认 GitLab Runner 与 GitLab 使用相同版本。
coordinator 是什么
coordinator 指 Runner 请求任务的 GitLab 实例。Runner 是一个独立代理,通过 GitLab API 从 coordinator 获取作业。
Windows 服务的日志保存在哪里
GitLab Runner 以 Windows 服务运行时,会写入系统事件日志。可以在“运行”中输入 eventvwr.msc,或搜索“事件查看器”,然后打开“Windows 日志 > 应用程序”。Runner 日志的来源为 gitlab-runner。
Windows Server Core 中,可使用 PowerShell 查看最近 20 条记录:get-eventlog Application -Source gitlab-runner -Newest 20 | format-table -wrap -auto。
启用调试日志
调试日志可能带来严重安全风险,因为其中包含作业可访问的全部变量和其他秘密信息。应关闭可能将这些日志传给第三方的日志聚合功能。掩码变量能够保护作业日志中的秘密值,但不能保护容器日志。
从命令行启用
以 root 登录终端后执行下列命令。
警告:不要在采用 Shell executor 的 Runner 上执行这种操作,因为它会重新定义 systemd 服务,并使所有作业以 root 运行。这既有安全风险,也会改变文件所有权,增加恢复为非特权账户的难度。
gitlab-runner stop
gitlab-runner --debug run
在 config.toml 中启用
在 config.toml 的全局配置节设置 log_level = "debug"。将这一行放在文件顶部,位于 concurrent 附近:
log_level = "debug"
在 Helm Chart 中启用
如果通过 GitLab Runner Helm Chart 安装在 Kubernetes 中,在 values.yaml 配置中设置 logLevel:
## Configure the GitLab Runner logging level. Available values are: debug, info, warn, error, fatal, panic
## ref: https://docs.gitlab.com/runner/configuration/advanced-configuration/#the-global-section
##
logLevel: debug
日志中的关联 ID
GitLab Runner 为每个 API 请求生成关联 ID,用于追踪与 GitLab 的交互。
如果 GitLab 响应的 X-Request-Id 头包含关联 ID,日志使用该值,通常为 ULID。如果响应没有该头,Runner 会使用自己为请求生成的 UUID,格式为不带连字符的小写十六进制。
出现回退关联 ID,表示请求未到达 GitLab Workhorse。故障很可能发生在中间环节,例如 WAF、CDN、负载均衡器或代理。
可以用关联 ID 对照不同组件的日志,追踪请求路径。查找 Runner 日志中的 correlation_id,再在 GitLab 服务端日志中搜索相同 ID。示例:
# Valid correlation ID (ULID format from GitLab API response)
Appending trace to coordinator...ok correlation_id=01KKDQ7P6TRW7Z6P2PWG5808EK job=101162491 status=202 Accepted
# Fallback correlation ID (lowercase hex UUID without dashes, generated by runner)
WARNING: Appending trace to coordinator... job failed correlation_id=21fe32aee0e146c194640b075c95ec7c job=101162868 status=403 Forbidden
为 Docker executor 配置 DNS
使用 Docker executor 时,宿主机上的 Runner 守护进程可以访问 GitLab,并不代表容器也能访问。一个常见原因是宿主机 DNS 配置没有传入容器。
例如,GitLab 服务与 Runner 位于两个网络,两者既可经公网通信,也可通过 VPN 通信。Runner 的路由可能使用默认公网 DNS,而非 VPN 内的 DNS,进而出现:
Created fresh repository.
++ echo 'Created fresh repository.'
++ git -c 'http.userAgent=gitlab-runner 16.5.0 linux/amd64' fetch origin +da39a3ee5e6b4b0d3255bfef95601890afd80709:refs/pipelines/435345 +refs/heads/master:refs/remotes/origin/master --depth 50 --prune --quiet
fatal: Authentication failed for 'https://gitlab.example.com/group/example-project.git/'
在这个例子中,认证失败来自公网与 GitLab 之间的中间服务,该服务要求另一套凭据;使用 VPN 内 DNS 则可以走向 GitLab 的另一条正常网络路径。
可在 Runner 的 config.toml 中,通过 [runners.docker] 的 dns 设置指定 Docker 使用的 DNS 服务器:
dns = ["192.168.xxx.xxx","192.168.xxx.xxx"]
x509: certificate signed by unknown authority
遇到证书由未知机构签发的错误,参阅自签名证书配置。
访问 /var/run/docker.sock 时 Permission Denied
使用 Docker executor 连接服务器上的 Docker Engine 时,如果访问套接字被拒绝,常见原因是 SELinux。CentOS、Fedora、RHEL 默认启用 SELinux,应查看系统策略及是否存在拒绝记录。
Docker Machine 无法查询 Docker 版本
错误为 Unable to query docker version: Cannot connect to the docker engine endpoint. 时,问题通常与机器创建有关,可能包括以下原因。
第一,TLS 失败。安装 docker-machine 后,某些证书可能无效。原文给出的处理方式是删除相关证书并重启 Runner:
sudo su -
rm -r /root/.docker/machine/certs/*
service gitlab-runner restart
重启后,Runner 发现证书为空,会重新创建证书。
第二,创建的机器主机名超过系统限制。例如 Ubuntu 的 HOST_NAME_MAX 为 64 个字符。可以用 docker-machine ls 查看主机名,检查 Runner 配置中的 MachineName,必要时缩短。
这种错误也可能出现在目标机器尚未安装 Docker 时。
SSH 隧道连接失败
dialing environment connection: ssh: rejected: connect failed (open failed) 表示 Docker 自动伸缩执行器通过 SSH 隧道无法连接目标系统的 Docker 守护进程。
应确认可以 SSH 登录目标系统,并成功运行 docker info 等 Docker 命令。
为自动伸缩 Runner 添加 AWS Instance Profile
创建 AWS IAM Role 后,IAM 控制台会显示 Role ARN 和 Instance Profile ARN。这里必须使用 Instance Profile 的名称,而不是 Role Name。
在 [runners.machine] 中添加 "amazonec2-iam-instance-profile=<instance-profile-name>",。
Docker executor 构建 Java 项目时超时
最可能的原因是 aufs 存储驱动的问题,见 Java 进程在容器内挂起的讨论。原文建议将存储驱动改为 OverlayFS,速度较快,或 DeviceMapper,速度较慢。
可参考 Docker 守护进程配置和通过 systemd 配置服务。
上传制品时返回 411
GitLab Runner 使用 Transfer-Encoding: chunked,而早期 NGINX 版本对此支持存在问题,见相关说明。应升级 NGINX,更多背景见 Runner issue 1031。
其他制品上传错误如何调试
制品从构建环境直接上传到 GitLab,绕过 GitLab Runner 进程。例如,Docker executor 从 Docker 容器上传;Kubernetes executor 从构建 Pod 内的构建容器上传。
因此,构建环境到 GitLab 的网络路径,可能与 Runner 进程到 GitLab 的路径不同。必须确保上传路径上的所有组件允许构建环境向 GitLab 发出 POST 请求。
默认情况下,上传器只记录上传 URL 和响应状态码,不足以判断是哪个系统阻止了上传。可为上传过程启用调试日志,查看响应头和正文。响应正文的日志上限为 512 字节。此功能可能暴露敏感数据,只应在调试期间开启。
如果请求已到达 GitLab,但返回非成功状态码,应进一步调查 GitLab 实例本身。常见问题见制品上传故障排查。
No URL provided,缓存无法下载或上传
出现 No URL provided, cache will not be download 或对应上传提示时,Runner helper 可能收到无效 URL,或没有获得访问远程缓存的预签名 URL。
检查 config.toml 的缓存配置,以及对应云服务的键和值。任何不符合 URL 语法的字段都可能拼出无效地址。
同时确认 helper 的 image 与 helper_image_flavor 匹配,并已更新。如果凭据配置有误,GitLab Runner 进程日志会包含诊断信息。
克隆时提示仓库为空
通过 HTTP 或 HTTPS 执行 git clone 时,无论由 Runner 执行还是手动测试,都可能看到:
$ git clone https://git.example.com/user/repo.git
Cloning into 'repo'...
warning: You appear to have cloned an empty repository.
应检查 GitLab 服务端的 HTTP 代理配置。自行配置代理时,请求必须转发到 GitLab Workhorse 套接字,而不是 GitLab Unicorn 套接字。
HTTP(S) Git 协议由 Workhorse 处理,因此它是 GitLab 的主要入口。使用 Linux 软件包安装、但不使用内置 NGINX 时,参阅使用外部 Web 服务器。GitLab Recipes 提供 Apache 和 NGINX 配置示例。
源码安装同样应参考上述文档,确保全部 HTTP(S) 流量经过 Workhorse。另见用户问题示例。
配置时区后提示 zoneinfo.zip 不存在
可以为 [[docker.machine.autoscaling]] 的时间段配置时区。大多数 Unix 系统无需额外操作即可使用,但部分 Unix 系统和多数非 Unix 系统,包括 Windows,可能在启动时失败:
Failed to load config Invalid OffPeakPeriods value: open /usr/local/go/lib/time/zoneinfo.zip: no such file or directory
原因来自 Go 的 time 包,它需要 IANA 时区数据库。多数 Unix 系统将其放在 /usr/share/zoneinfo、/usr/share/lib/zoneinfo 或 /usr/lib/locale/TZ/。Go 会依次查找这些位置;如果找不到,但机器装有 Go 开发环境,则回退到 $GOROOT/lib/time/zoneinfo.zip。
如果所有位置都不存在,例如某些生产 Windows 主机,就会出现上述错误。
系统支持 IANA 时区数据库、但尚未安装时,可以安装它。Linux 示例:
# on Debian/Ubuntu based systems
sudo apt-get install tzdata
# on RPM based systems
sudo yum install tzdata
# on Linux Alpine
sudo apk add -U tzdata
系统没有原生时区数据库时,可按以下步骤让 OffPeakTimezone 工作:
- 下载 zoneinfo.zip。自 v9.1.0 起,也可以把 URL 中的
latest替换为具体标签,例如v9.1.0。 - 将文件保存到固定目录,建议与
config.toml同目录。例如配置位于C:\gitlab-runner\config.toml,则保存为C:\gitlab-runner\zoneinfo.zip。 - 设置
ZONEINFO环境变量,值为该 ZIP 文件的完整路径。
使用 run 命令启动 Runner 的 Unix 示例:
ZONEINFO=/etc/gitlab-runner/zoneinfo.zip gitlab-runner run <other options ...>
Windows 示例:
C:\gitlab-runner> set ZONEINFO=C:\gitlab-runner\zoneinfo.zip
C:\gitlab-runner> gitlab-runner run <other options ...>
如果以系统服务运行,需要更新或覆盖服务配置。Unix 上通过服务管理器设置;Windows 上通过系统设置,将 ZONEINFO 加入运行 Runner 的用户环境变量。
为什么无法运行多个 Runner 实例
可以运行多个实例,但不能共用同一个 config.toml。多个 Runner 同时使用同一配置文件,会产生难以调试的异常行为。任何时刻,一个配置文件只能被一个 Runner 实例使用。
作业开始前出现明显延迟
如果部分项目的作业迟迟不启动,而其他项目立即运行,可能是长轮询问题。
典型现象包括:
- 作业排队时间异常长,通常接近 GitLab 实例的长轮询超时时间。
- 部分 Runner 看似卡住,其他 Runner 正常。
- 日志出现
CONFIGURATION: Long polling issues detected。
原因是 Runner worker 被长轮询请求占用,无法及时处理其他作业。不同配置下,影响可能从性能瓶颈发展到完全死锁。这与 GitLab Workhorse 的 apiCiLongPollingDuration 设置有关,默认值为 50 秒。
多种配置组合都可能触发该问题,完整原因、示例和解决方案见长轮询问题。
preparing environment 阶段出现系统失败
Job failed (system failure): preparing environment: 往往与 Shell 加载用户配置文件有关,其中某个脚本导致执行失败。已知可能造成问题的文件包括 .bash_logout、.condarc 和 .rvmrc。
SELinux 也可能是原因,可以查看审计日志:
sealert -a /var/log/audit/audit.log
Cleaning up 阶段后 Runner 突然结束
原文记录,CrowdStrike Falcon Sensor 启用“container drift detection”时,可能在作业的“Cleaning up files”阶段后终止 Pod。原文给出的解决方案是关闭该设置,使作业能够完成。此设置属于安全产品配置,实际调整时应纳入组织安全管理流程。
remote error: tls: bad certificate
remote error: tls: bad certificate (exec.go:71:0s) 可能发生于生成制品的作业中系统时间大幅变化。时间变化使 SSL 证书被判断为过期,上传制品时便会失败。
应在作业结束前将系统时间恢复为有效日期与时间,以便上传时完成 SSL 验证。由于制品文件的创建时间也发生了变化,它们会被自动归档。
Helm Chart 出现 Unauthorized
卸载或升级通过 Helm 部署的 Runner 前,应先在 GitLab 中暂停 Runner,并等待现有作业全部完成。
如果作业仍在运行就执行 helm uninstall 或 helm upgrade 删除 Runner Pod,作业结束时可能出现:
ERROR: Error cleaning up pod: Unauthorized
ERROR: Error cleaning up secrets: Unauthorized
ERROR: Job failed (system failure): Unauthorized
可能的原因是 Runner 被移除时,其角色绑定也被删除。作业 Pod 持续运行到结束,但 Runner 随后尝试删除它时,已失去所需权限。详情见 Chart issue 225。
Elasticsearch 提示 vm.max_map_count 太低
Elasticsearch 服务容器启动时,可能提示 max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]。
必须在实际运行 Elasticsearch 的实例上设置 vm.max_map_count,不同平台的正确配置方式见 Elasticsearch 文档。
docker+machine 执行器准备失败
出现 Preparing the "docker+machine" executor ERROR: Preparation failed: exit status 1,可能意味着 Docker Machine 无法创建执行器虚拟机。
为获得详细错误,可以使用与 config.toml 中相同的 MachineOptions 手动创建机器,例如:docker-machine create --driver=google --google-project=GOOGLE-PROJECT-ID --google-zone=GOOGLE-ZONE ...。
No unique index found for name
创建或更新 Runner 时,如果数据库 tags 表缺少唯一索引,可能出现此错误。GitLab 界面也可能提示 Response not successful: Received status code 500。
长期经历多次大版本升级的实例可能受影响。可使用 gitlab:db:deduplicate_tags Rake 任务合并重复标签。另见 Rake 任务文档。
不允许执行 sts:AssumeRoleWithWebIdentity
如果为 Runner 的 Kubernetes ServiceAccount 配置了 IAM 角色,但日志提示无法执行 sts:AssumeRoleWithWebIdentity,可能看到:
{"error":"Not authorized to perform sts:AssumeRoleWithWebIdentity","level":"error","msg":"error while generating S3 pre-signed URL","time":"2025-10-15T18:07:20Z"}
原因是 IAM 角色可信实体配置中的 StringLike 或 StringEquals 条件包含了 https://。从 OIDC URL 中移除此前缀即可:
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringLike": {
"oidc.eks.<AWS_REGION>.amazonaws.com/id/<OIDC_ID>:sub": "system:serviceaccount:<NAMESPACE>:<SERVICE_ACCOUNT>"
}
}
原文来源:Troubleshooting GitLab Runner。本文依据留存原文译为中文,代码示例按原文保留。
原文由 GitLab 提供,文档许可为 Creative Commons Attribution-ShareAlike 4.0 International(CC BY-SA 4.0)。本文为中文翻译,遵循相同许可。











暂无评论内容