小团队 CI runner 排队:从镜像拉取到缓存策略的排查记录

最近遇到一个很有迷惑性的 CI 问题:小团队自建了两台 runner,平时单个分支跑测试没问题,但一到几个人同时提 MR,队列就越来越长。

一开始大家以为是测试变慢了。看完日志才发现,很多 job 的脚本还没开始执行,时间先花在这里:

text 复制代码
Preparing environment
Pulling docker image node:20 ...
Pulling docker image postgres:16-alpine ...
context deadline exceeded

这篇不讲大而全的 CI 优化,只记录我会怎么排"runner 排队"和"镜像拉取慢"这两件事。

先拆流水线阶段

我先把 job 耗时拆成三段:

阶段 表现 常见原因
pending 等 runner 接任务 runner 少、tag 不匹配、并发限制
preparing runner 接了,但在准备环境 拉基础镜像、service 镜像、DNS、网络
script 脚本开始执行 测试慢、缓存没命中、数据库初始化慢

这次真正慢的是 preparing,不是 script。

一个典型 .gitlab-ci.yml

示例配置大概这样:

yaml 复制代码
test:
  image: node:20
  services:
    - name: postgres:16-alpine
      alias: postgres
    - name: redis:7-alpine
      alias: redis
  script:
    - npm ci
    - npm test

并发一上来,runner 要同时拉 nodepostgresredis。如果还有 e2e、扫描、构建 job,镜像来源会更多:

  • Docker Hub:基础镜像、数据库镜像。
  • GHCR:团队工具镜像。
  • MCR:Playwright / 浏览器测试镜像。
  • Quay:安全扫描或云原生工具镜像。

单个 job 慢 30 秒不明显,6 个 job 一起慢,队列就会明显变长。

先在 runner 节点复现

不要只盯着 CI 页面。我会直接到 runner 节点跑:

bash 复制代码
docker pull node:20
docker pull postgres:16-alpine
docker pull redis:7-alpine
docker pull mcr.microsoft.com/playwright:v1.44.0-jammy

如果这里就卡住,说明不是 GitLab 本身的问题,而是 runner 节点拉镜像这层不稳定。

配镜像源和多源入口

runner 是 Docker executor 时,可以先处理 Docker 镜像源:

bash 复制代码
curl -sSL https://static.1ms.run/1ms-helper/install.sh | bash
sudo 1ms-helper config:docker

然后验证常用镜像:

bash 复制代码
docker pull docker.1ms.run/library/node:20
docker pull docker.1ms.run/library/postgres:16-alpine
docker pull docker.1ms.run/library/redis:7-alpine

如果有 GHCR:

bash 复制代码
docker pull ghcr.1ms.run/your-org/e2e-runner:2026.05

我会把这组验证命令放进 runner 节点初始化文档。这样新加 runner 时,不用等第一条流水线失败才发现镜像入口没跑通。

pull policy 和缓存别乱配

GitLab Runner Docker executor 支持 pull_policy。但这不是一个"越不拉越好"的选项。

我一般这样分:

镜像 策略
高频基础镜像 固定 tag,允许本地缓存复用
团队自建测试镜像 使用版本号,不长期用 latest
安全扫描镜像 固定版本,关键链路记录 digest
临时实验镜像 可以每次拉,但不要进主干发布链路

示例:

toml 复制代码
[[runners]]
  executor = "docker"
  [runners.docker]
    image = "docker.1ms.run/library/node:20"
    pull_policy = ["if-not-present", "always"]

这个配置不是万能答案,重点是让团队知道:哪些镜像需要新鲜,哪些镜像应该稳定。

安全扫描镜像别随手 latest

最近几个月,安全扫描、IaC 扫描这类工具镜像也出现过供应链事件。CI 里这些镜像权限往往不低,还能接触代码和构建产物,所以不要把它们当普通工具随便拉。

我现在会对扫描镜像做三件事:

  • 固定版本 tag。
  • 升级走 MR。
  • 发布链路记录 digest。

这和镜像源加速不是同一件事:前者解决可控性,后者解决可达性。runner 想跑得稳,两层都要看。

最后复盘

这次真正的瓶颈不是测试脚本,而是 runner 公共入口太脆弱。每个人都在提 MR,但每条流水线都要重复拉镜像,镜像入口不稳定时,就会把团队并行效率拖下来。

我会把 runner 初始化分成四步:

  1. 配 Docker 镜像源。
  2. 预拉高频基础镜像。
  3. 固定工具镜像版本。
  4. 用一组 docker pull 验证多源入口。

这个动作不花哨,但对小团队很实用。测试优化之前,先让 runner 稳定把环境拉起来。

相关推荐
神奇小汤圆10 小时前
解放双手!SpringBoot 6种自动填充公共字的手段,这些代码真没必要手写!
后端
鱼人11 小时前
多态底层原理:向上转型、动态绑定,一文彻底搞懂
后端
神奇小汤圆11 小时前
吃透Redis缓存核心:淘汰策略、LRU/LFU区别与四大缓存问题全解
后端
无责任此方_修行中11 小时前
搓了一个国产大模型与 AI Agent 比价工具
前端·后端·ai编程
yunyi12 小时前
改个 SSH 端口,我把自己锁在了服务器外面
运维·后端
元界metalite12 小时前
MyBatis多数据源常见难题-事务开始了为何数据源还没选出来
后端·mybatis
orient12 小时前
ForkJoin 框架源码深度解析:工作窃取 + RecursiveTask 实战
后端
karry_k12 小时前
Skill 到底是什么?从提示词、脚本到多智能体工作流的完整指南
java·人工智能·后端
人间凡尔赛13 小时前
eBPF + WebAssembly 正在重写服务网格数据平面:2026 云原生架构的“去 Sidecar“革命
后端·云原生·架构