1. 问题背景:当Runner突然"罢工"时

作为持续集成流水线的核心中的超级核心,GitLab Runner在代码构建、测试、部署等场景中承担着核心任务。但在实际使用中(尤其是在资源受限的服务器上),我们经常会遇到这样的场景:

  • 自动化构建突然中断
  • 高并发任务执行时多个Runner集体宕机
  • 长时间运行的测试任务神秘消失

本文将以Shell执行器的Linux环境为例(技术栈:GitLab Community Edition 15.6 + Runner 15.6.0),演示如何像侦探一样排查Runner异常停止的"犯罪现场"。


2. 现场勘查:三招定位停止原因

2.1 查看Runner服务日志

# 查看实时日志(systemd系统)
$ journalctl -u gitlab-runner.service -f

# 典型错误日志示例:
# Jul 15 10:23:45 CI-Server gitlab-runner[14257]: ERROR: Failed to process runner... 
# Jul 15 10:23:45 CI-Server gitlab-runner[14257]: FATAL: OOM error: cannot create new OS thread

关键点:关注ERRORFATAL级别的日志,内存不足(OOM)、端口冲突、权限错误是常见元凶

2.2 检查作业日志残留

# 进入Runner工作目录
$ cd /home/gitlab-runner/builds/

# 查找未完成的作业目录
$ find . -name ".job.log" -mtime -1 | xargs grep "ERROR: Job failed"

示例输出

./abc1234/.job.log:ERROR: Job failed: exit status 137

解密:exit code 137通常表示进程被强制终止(128+9=SIGKILL)

2.3 系统资源监控取证

# 查看历史内存使用(需安装sysstat)
$ sar -r -f /var/log/sysstat/sa15

# 检查进程被杀记录
$ grep -i 'killed process' /var/log/messages

典型证据

Jul 15 10:23:45 CI-Server kernel: Out of memory: Killed process 14257 (gitlab-runner)

3. 起死回生:三种恢复方案实战

3.1 快速重启方案(治标)

# 优雅重启服务(保留正在执行的作业)
$ gitlab-runner restart

# 强制重启(立即终止所有进程)
$ systemctl stop gitlab-runner
$ pkill -9 gitlab-runner  # 清理残留进程
$ systemctl start gitlab-runner

适用场景:临时性资源问题,需要快速恢复服务

3.2 进程级深度清理(治本)

# 查找僵尸进程
$ ps aux | grep 'defunct' | grep -v grep

# 清理示例(假设发现残留的bash进程)
$ pstree -p | grep gitlab-runner
# |-gitlab-runner(14257)-+-sh(14300)-+-git(14301)
# |                     |-bash(14302)

$ kill -9 14302  # 终止卡死的子进程
$ gitlab-runner verify  # 验证服务状态

特殊技巧:使用lsof查找被占用的文件描述符:

$ lsof -p $(pidof gitlab-runner) | grep deleted

3.3 配置调优方案(预防)

修改/etc/gitlab-runner/config.toml

concurrent = 4  # 根据CPU核心数调整(建议物理核心数×2)

[[runners]]
  executor = "shell"
  [runners.custom_build_dir]
  [runners.cache]
    MaxUploadedArchiveSize = 0  # 禁用缓存(当磁盘满时)
  [runners.shell]
    memory_limit = 4096  # 限制单个作业内存(单位MB)

参数解析

  • concurrent:控制同时运行的作业数
  • memory_limit:防止单个作业耗尽内存
  • MaxUploadedArchiveSize:解决磁盘写满导致失败

4. 应用场景与关联技术

4.1 典型故障场景

场景特征 推荐解决方案 相关指标阈值
周期性OOM错误 内存限制+作业分流 内存使用>90%
SSH连接超时 心跳检测+超时设置 timeout=3600s
磁盘空间不足 缓存清理+日志轮转 inode使用>80%

4.2 关联技术:资源监控集成

# 实时监控脚本示例(保存为monitor_runner.sh)
#!/bin/bash
ALERT_THRESHOLD=90

while true; do
    MEM_USAGE=$(free | awk '/Mem/{print $3/$2*100}')
    if (( $(echo "$MEM_USAGE > $ALERT_THRESHOLD" | bc -l) )); then
        echo "$(date) - 内存使用率过高: ${MEM_USAGE}%" >> /var/log/runner_monitor.log
        gitlab-runner stop --all
    fi
    sleep 300
done

5. 技术方案对比分析

5.1 方案优缺点

方案类型 优点 缺点 适用阶段
快速重启 恢复速度快(<1min) 可能丢失作业上下文 生产环境紧急处理
进程清理 精准定位问题点 需要专业知识 开发测试环境
配置调优 预防性效果显著 需要性能测试 长期运行维护

5.2 性能测试数据参考

在4核8G服务器上的压力测试结果:

并发数 | 平均响应时间 | 失败率
---------------------------------
  2    |     23s     |  0%
  4    |     41s     |  5%
  8    |     TIMEOUT |  100%

结论:建议并发数设置为CPU逻辑核心数的1.5-2倍


6. 必须知道的注意事项

  1. 日志文件轮转:默认日志可能撑爆磁盘
# 配置logrotate(/etc/logrotate.d/gitlab-runner)
/home/gitlab-runner/.gitlab-runner/*.log {
    daily
    rotate 7
    missingok
    compress
}
  1. 权限安全陷阱
# 错误示范:
$ chmod 777 /home/gitlab-runner  # 可能引发提权漏洞

# 正确做法:
$ sudo -u gitlab-runner gitlab-runner install
  1. 跨版本升级风险
# 正确的升级姿势:
$ gitlab-runner stop
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
$ apt-get install gitlab-runner=15.6.0

7. 事后的总结

通过本文的"现场勘查三部曲"和"复活三式",我们已经建立了从故障发现到恢复的完整链路。但真正的运维高手还需要:

  1. 建立预警机制:配置Prometheus+Alertmanager监控
  2. 实施混沌工程:定期模拟故障场景
  3. 版本控制:严格测试Runner升级版本

未来的持续集成系统正在向弹性伸缩方向发展,结合Kubernetes的自动扩缩容能力,可以期待Runner集群的智能自愈功能。但在那之前,掌握这些底层排查技能仍然是每个DevOps工程师的必修课。

记住:每个神秘的Runner崩溃背后,都有日志留下的线索。愿你的持续集成流水线永远畅通无阻!