csdn-enterpriseGitLab Runner docker pull 慢:并行流水线镜像拉取排查

1. 问题现象

团队并行提交多个 MR 后,GitLab Runner 队列开始变长。业务测试本身没有明显变慢,但 job 卡在环境准备阶段:

text 复制代码
Preparing environment
Using Docker executor with image node:20 ...
Pulling docker image node:20 ...
context deadline exceeded

这类问题不要一上来就改测试脚本。先确认到底是测试执行慢,还是 runner 在拉镜像时已经被拖住。

本文记录一套排查顺序:从 runner executor、基础镜像、service 镜像、pull policy、镜像源和本地缓存逐层检查。

2. 环境示例

text 复制代码
GitLab Runner: Docker executor
Runner 节点:Linux / Docker Engine
并发场景:多个分支同时跑单测和集成测试
常见镜像:node:20、python:3.12、postgres:16-alpine、redis:7、ghcr.io/.../test-runner

如果是 GitHub Actions 自建 runner,也可以参考同样的排查思路。核心都是:job 开始前要先把容器镜像拉到 runner 节点。

3. 先区分 pending、preparing 和 script

看 job 卡在哪一段:

阶段 现象 方向
pending 没有 runner 接任务 runner 数量、tag、并发数
preparing 已分配 runner,正在拉镜像 Docker、镜像源、DNS、缓存
script 脚本已经执行 测试耗时、依赖缓存、数据库初始化

如果日志里出现 Pulling docker image,说明至少有一部分时间花在镜像拉取。

4. 在 runner 节点手工验证

进入 runner 节点,不通过 CI,直接拉关键镜像:

bash 复制代码
docker pull node:20
docker pull python:3.12
docker pull postgres:16-alpine
docker pull redis:7-alpine

如果团队使用 GHCR、MCR、Quay:

bash 复制代码
docker pull ghcr.io/your-org/test-runner:latest
docker pull mcr.microsoft.com/playwright:v1.44.0-jammy
docker pull quay.io/skopeo/stable:latest

常见错误包括:

text 复制代码
context deadline exceeded
i/o timeout
connection reset by peer
TLS handshake timeout

这时问题优先看 runner 节点的网络、DNS、镜像源和代理配置。

5. 配置 Docker 镜像源

可以先用 1ms-helper 处理 Docker 场景:

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

Linux Docker 的基础配置可以参考:

json 复制代码
{
  "registry-mirrors": ["https://docker.1ms.run"],
  "dns": ["8.8.8.8", "114.114.114.114"]
}

然后重启 Docker:

bash 复制代码
systemctl daemon-reload
systemctl restart docker
systemctl status docker

再验证:

bash 复制代码
docker pull docker.1ms.run/library/node:20
docker pull docker.1ms.run/library/postgres:16-alpine
docker pull ghcr.1ms.run/your-org/test-runner:latest

说明:毫秒镜像在这里解决的是多源镜像入口和拉取稳定性这一层,不替代 runner 并发、测试拆分和依赖缓存。

6. 检查 GitLab Runner pull policy

GitLab Runner Docker executor 支持 pull_policy。如果每次 job 都强制拉镜像,runner 本地缓存就很难发挥作用。

示例:

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

实际生产里不要简单照抄。建议按镜像类型区分:

镜像类型 建议
高频基础镜像 固定 tag,配合本地缓存
安全扫描镜像 固定版本,关键场景考虑 digest
数据库 service 镜像 固定小版本,减少重复拉取
团队自建镜像 使用内部版本号,不长期依赖 latest

7. 检查 .gitlab-ci.yml

一个常见配置:

yaml 复制代码
test:
  image: docker.1ms.run/library/node:20
  services:
    - name: docker.1ms.run/library/postgres:16-alpine
      alias: postgres
  script:
    - npm ci
    - npm test

如果每个 job 都启动独立数据库 service,且并发很多,镜像拉取、容器启动、数据库初始化都会叠加。需要结合缓存、测试拆分和服务复用一起看。

8. 固定关键镜像版本

近期 Docker 官方复盘过 Trivy 和 KICS 相关的供应链攻击事件。CI 里常见的扫描器、构建器、测试工具镜像,不建议长期用模糊的 latest

至少做到:

  • 生产发布链路用明确 tag。
  • 关键扫描和构建镜像记录 digest。
  • 基础镜像升级走 MR,而不是静默变化。
  • runner 节点定期清理,但不要把高频镜像缓存清得太干净。

Docker 支持按 digest 拉取镜像,例如:

bash 复制代码
docker pull alpine@sha256:<digest>

Digest 不是为了让镜像拉得更快,而是为了让 CI 结果更可复现。

9. 排查清单

检查项 命令/位置
runner 是否接任务 GitLab job 状态、runner tag
是否卡在镜像 job 日志里的 Pulling docker image
Docker 是否正常 systemctl status docker
DNS 是否异常 1ms-helper check:dns
基础镜像能否拉取 docker pull node:20
多源镜像能否拉取 docker pull ghcr.io/...
pull policy 是否合适 config.toml
service 镜像是否过多 .gitlab-ci.yml

总结

CI 并行构建变慢时,不要只看测试脚本。runner 的镜像拉取阶段经常是隐藏瓶颈。

我的处理顺序是:

  1. 看 job 卡在 pending、preparing 还是 script。
  2. 在 runner 节点手工拉基础镜像和 service 镜像。
  3. 配置 Docker 镜像源并验证多源镜像入口。
  4. 检查 pull_policy 和本地缓存。
  5. 固定关键工具镜像版本,必要时记录 digest。

这样才能把"测试慢"和"runner 拉镜像慢"分开处理。

相关推荐
一只大袋鼠3 小时前
Git (三):Tag 标签管理、图形工具、IDEA 集成与 GitLab 私有化部署
开发语言·git·gitlab
雪度娃娃3 小时前
Asio异步读写——简单服务器和客户端异步通信
运维·服务器·网络·c++·php
sbjdhjd4 小时前
02 下 | Kubernetes Pod 实战实验完全解析
linux·运维·云原生·kubernetes·podman·kubelet·kubeless
Achou.Wang4 小时前
Docker 多阶段构建:优化 Go 应用镜像大小的最佳实践
elasticsearch·docker·golang
酷道4 小时前
获取Docker阿里云专属镜像加速地址
阿里云·docker·容器·云计算
古城小栈4 小时前
K8s 存储组件 通俗精讲
云原生·容器·kubernetes
陳10304 小时前
Linux:System V 消息队列与信号量
linux·运维·服务器
云飞云共享云桌面4 小时前
SolidWorks 服务器通过云飞云共享云桌面10人研发共享方案
运维·服务器·3d·设计模式·电脑
条俐开水喉4 小时前
高密度AI算力服务器机房U位动态调度管理方案
运维·服务器·人工智能