跳到正文
cyxc.club

记录一次容器镜像拉取一直卡住的问题

/ 约 18 分钟

目录

2026-09-11。三台节点 k8s-10-1-16-2110.1.16.21)、k8s-10-1-16-22k8s-10-1-16-23。GitLab Operator chart 10.3.2,升到 19.3.2。gitlab-toolbox / gitlab-migrations 长时间 PodInitializing,主容器一直 Pulling,既没有 Pulled 也没有 Failed。当时看起来像 Harbor 下不动大层。下面按当天怎么查的写;命令和数字可以原样复现。节点 PATH/opt/kube/bin。SSH:ssh root@10.1.16.212223

目录


现象

当时:

gitlab-migrations-a3aba68-e90-9-pre-96skt PodInitializing k8s-10-1-16-21
gitlab-toolbox-76f597b7f6-bmvmm PodInitializing k8s-10-1-16-22
gitlab-migrations-f354d9f-e90-7-dbpxk Completed k8s-10-1-16-21
Terminal window
kubectl -n gitlab get pods,jobs -o wide | grep -E 'toolbox|migrat'
kubectl -n gitlab get events --sort-by=.lastTimestamp \
| grep -iE 'toolbox-ce|Pulling|Pulled|Failed|ErrImage'
kubectl -n gitlab describe pod <卡着的 pod> | tail -40

describe:init 的 certificates / gitlab-base 已经 already present,主容器:

Pulling image "harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2"

十几分钟既没有 Pulled 也没有 Failed。kubelet 卡在一次 CRI pull 上。journalctl -u kubelet --since "30 min ago" 几乎没有 Pulling,以 events / describe 为准。

事件里同时有两个仓库(已删除的 Pod 只出现在 events):

Pulling image "registry.gitlab.com/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2"
Pulling image "harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2"
对象 镜像 节点
Job gitlab-migrations-300ebb3-e90-8-pre Pod …-clqgl GitLab.com v19.3.2 16.21
同一 Job Pod …-qm644 GitLab.com v19.3.2 16.22
gitlab-migrations-a3aba68-e90-9-pre Harbor v19.3.2 16.21
gitlab-toolbox-76f597b7f6-bmvmm Harbor v19.3.2 16.22
gitlab-migrations-f354d9f-e90-7 Completed GitLab.com v19.3.0 16.21

300ebb3 在 21、22 各有一个 Pod。已删除的对象只出现在 events 里,只看当前 Pod 会漏掉 GitLab.com 那一行。


时间线(CST,UTC+8)

时间 发生了什么
21:08–21:45 从 Harbor 预拉一遍 19.3.2 CNG(urllib 走 /v2/)。toolbox:31 层、1032.5 MiB、169.9s,amd64 digest sha256:4cc3659714b1…。脚本 13:08:02–13:45:25 UTC,结束码 0
21:46:15 Job gitlab-migrations-300ebb3-e90-8-pre 创建(2026-09-11 13:46:15 UTC,UID e77696f3-a9bc-4cde-85b4-194d7fea165f),镜像 registry.gitlab.com/.../gitlab-toolbox-ce:v19.3.2
21:46:16 ReplicaSet gitlab-toolbox-76f597b7f6 创建(13:46:16Z,rev 4),镜像已是 Harbor …/gitlab-toolbox-ce:v19.3.2
21:46 16.22 ingest 开始,ref 已是 layer-sha256:bf390218420b…(与 Job 创建同一分钟)
22:00:35 16.21 同一层 ingest 开始
~22:07 Job gitlab-migrations-a3aba68-e90-9-pre 在拉 Harbor(values 哈希 e90-8e90-9Successfully pulled 14:22:57Z,含等待 16m19s,倒推拉取约 14:06:38Z)
22:14 有人问 Harbor 上这张镜像能不能拉
~22:15 16.23 上 crictl pull Harbor 成功(本机,不是 21/22)
22:17 指出 bf390218420b 这层会卡住 download
22:18 16.21 timeout 60 crictl pull 失败;ss 里 containerd 钉在 34.149.22.116:443
22:20 16.21 ingest data ≈ 366 MiB / 733 MiB;16.22 ≈ 445 MiB。Recv-Q/Send-Q 都是 0
22:22 21、22 上 ss -K dst 34.149.22.116 dport 443(没带 sport)。300ebb3 两 Pod ErrImagePull / connection abort(14:21:58Z / 14:22:00Z)
22:23 crictl pull Harbor:Image is up to datea3aba68-e90-9-pre、toolbox 变成 Running
22:24 a3aba68-e90-9-pre Job completed(14:24:11Z)
22:27:06 post-migrations Job gitlab-migrations-a3aba68-e90-9 创建(14:27:06Z),22:28:32 完成
22:31 GitLab CR generation=9Initialized / Available14:31:18Z / 14:31:19Z

预拉脚本 toolbox 那一行:

==> harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2
index 685B -> amd64 sha256:4cc3659714b1...
OK layers=31 blobs=1032.5MiB 169.9s

预拉 21:45 结束,toolbox 的 blob 已经在 Harbor 里。21:46 起节点仍在 Pulling。


先别用 docker pull 当证据

本机(当时是 16.23)docker pull harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2 立刻失败:

Error response from daemon: Get "https://harbor.cyxc.club/v2/": EOF

docker manifest inspect 却能返回清单。Docker daemon 配了:

HTTP Proxy: http://10.1.10.11:7890
HTTPS Proxy: http://10.1.10.11:7890
No Proxy: localhost,127.0.0.1,easzlab.io.local,10.0.0.0/8,10.1.0.0/16,.local

NO_PROXY 没有 .cyxc.clubharbor.cyxc.club 解析到 10.1.10.3,但 daemon 仍把 HTTPS 送进代理,/v2/ 直接 EOF。~/.docker/config.json 的 auths 里只有 ghcr.ioregistry.cyxc.clubregistry.gitlab.cyxc.club,没有 Harbor;这次也不需要登录。

节点排查用 curl / crictl。K8s 的 containerd 不走这条 Docker 代理。TLS 正常:证书 CN harbor.cyxc.club,Let’s Encrypt YR1,2026-08-23 到 2026-11-21。

匿名探测 Harbor:

Terminal window
curl -sS -o /dev/null -w 'http:%{http_code}\n' https://harbor.cyxc.club/v2/
# 401,WWW-Authenticate: Bearer realm="https://harbor.cyxc.club/service/token",service="harbor-registry"

项目 gitlab 是 public,token 接口匿名就能发 pull token(这次 token 长度 786)。不要把 401 当成镜像不存在。

Terminal window
curl -sS 'https://harbor.cyxc.club/service/token?service=harbor-registry&scope=repository:gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:pull'

这张镜像在 Harbor 里什么样

清单是 fat manifest:linux/arm64 + linux/amd64

镜像 harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2
清单 digest sha256:37a75ea1cf23a17b6fb3c60dbc1409caaf466e5664565b53cf95f08495ca27fc
arm64 manifest sha256:367032bf84a6e063e0076d797990054a3527ad5d96ff973ae120fe560f3dadff size 6217
amd64 manifest sha256:4cc3659714b133908f024617cac3a32288ce5d7a83e87f443e75d6cb2ce59ca0 size 6217
amd64 config sha256:de9db0f2559c3ccfa4690b2ca4bea58ab76a6cfaf5516766b3ed9c58be43709a size 11775
amd64 层数 30(加上 config 预拉脚本数成 31)
层压缩合计 1082618030 B(1032.5 MiB)
落地 crictl imagesde9db0f2559c3,约 1.08GB
Harbor 制品 sha256:80cb989de853ac27ec9940dbc70259ad8ac687471a1c8c18b06f40b1199b41ef size 1082636456(制品元数据);events 里 Image size: 1082636707;层压缩合计 1082618030。三个数口径不同,差的是 config/元数据,不是下错了

docker manifest inspect / 带 token 的 GET /manifests/v19.3.2 都能拿到这份 list。

Harbor 项目 gitlabproject_id=7registry_id=5public=truerepo_count=16。上游 registry id=5 name=gitlab url=https://registry.gitlab.com status=healthy。这只说明层可以从 GitLab.com 进仓。Ingress 把 /v2/ 指到 harbor-core,不是 registry Pod;registry 的 S3 配了 disableredirect: true,blob 不会 307 到 RGW。这些和「节点连 34.149」不是同一条路径。

卡住的层是 amd64 第 18 条(下标 17),比其它层大一个数量级:

sha256:bf390218420b5dcdeed2d425c9594b46bc91e2885f6beca227fb9147b55a2887 768735388

完整 30 层见文末附录。HEAD 第一层和最后一层都是 200,Accept-Ranges: bytes。Range bytes=0-1048575bytes=536870912-537919487(512 MiB 附近)都是 206,RGW 对象没有在半截挖空。

16.23 上 ctr -n k8s.io images pull 17.9s 下完约 1005.6 MiB(56.2 MiB/s),随后 unpacking linux/amd64 sha256:37a75ea1…,被 timeout 30 打断。接着 crictl pull 成功:

Image is up to date for sha256:de9db0f2559c3ccfa4690b2ca4bea58ab76a6cfaf5516766b3ed9c58be43709a
harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce v19.3.2 de9db0f2559c3 1.08GB

必须用 crictlctr -n k8s.ioctr 默认 namespace kubelet 看不见。这就是「16.23 对照」的来源:本机先从 Harbor 拉完,不是这台节点天生没事。


Harbor 这一层能不能下完

在能解析 harbor.cyxc.club 的机器上跑,卡住节点上也跑一遍getent hosts harbor.cyxc.club 必须是 10.1.10.3

Terminal window
TOKEN=$(python3 -c 'import json,urllib.request;print(json.load(urllib.request.urlopen(
"https://harbor.cyxc.club/service/token?service=harbor-registry&scope=repository:gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:pull"
))["token"])')
DIGEST=sha256:bf390218420b5dcdeed2d425c9594b46bc91e2885f6beca227fb9147b55a2887
URL=https://harbor.cyxc.club/v2/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce/blobs/$DIGEST
# 必须 --max-redirs 0,才能看见有没有 307
curl -sS -D - -o /dev/null --max-redirs 0 -H "Authorization: Bearer $TOKEN" "$URL" | head -20
curl -sS --http1.1 -r 0-16777215 \
-w 'code=%{http_code} size=%{size_download} speed=%{speed_download} time=%{time_total} url=%{url_effective}\n' \
-o /dev/null -H "Authorization: Bearer $TOKEN" "$URL"
# 整层 HTTP/2 / HTTP/1.1
curl -sS --http2 -w 'http=%{http_code} ver=%{http_version} size=%{size_download} speed=%{speed_download} time=%{time_total}\n' \
-o /dev/null -H "Authorization: Bearer $TOKEN" "$URL"
curl -sS --http1.1 -w 'http=%{http_code} ver=%{http_version} size=%{size_download} speed=%{speed_download} time=%{time_total}\n' \
-o /dev/null -H "Authorization: Bearer $TOKEN" "$URL"

没有 python3 时,token 用前面的 curl/service/token。urllib 默认会 follow 307,要用 --max-redirs 0 或自己关 redirect。

探测 结果
HEAD / GET 不跟随 200,无 LocationContent-Length: 768735388Accept-Ranges: bytes
16.21 抽 16 MiB 206,0.535s,约 31.4 MiB/s,url_effective 仍是 Harbor
urllib HTTP/1.1 整层 768735388 B,9.5s,77.53 MiB/s
curl HTTP/2 整层 9.026s,约 81.2 MiB/s
curl HTTP/1.1 整层 8.887s,约 82.5 MiB/s
Traefik readTimeout/writeTimeout 已是 600s,不是默认 60s
Harbor 结果 含义
200/206,URL 仍是 harbor.cyxc.club,至少十几 MiB/s 仓、Traefik、RGW、HTTP/2 都排除
307 + Location: registry.gitlab.com 才是 proxy cache 回源(这次不是)
超时 / EOF / 极慢 才查 Traefik / registry / RGW(这次不是)

Harbor core 当时有:

Artifact: gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:, digest:sha256:367032bf… is not found in proxy cache, fetch it from remote repo

那是 arm64 manifest,和 bf390218420b 无关。registry 还有 blob unknown sha256:9c1e19b054454ab3f04fd08b8f9fa7cdd69d83f4e46908c4c4ea7e24edeee515,也不是这层。不要把 proxy cache 日志绑到卡住的 digest 上。


节点:对端不是 Harbor,ingest 卡在这一层

三台都看。ss 里 Process 必须是 containerd,节点上还有 kube-apiserver、speaker 等 443,不要看错。

Terminal window
export PATH=/opt/kube/bin:$PATH
getent hosts harbor.cyxc.club # 必须是 10.1.10.3
ss -tnp | grep containerd | grep -E '443|10.1.10.3|34.149'
# 挂死时 ESTAB,Recv-Q/Send-Q 往往都是 0
# 对端 IP 下次可能不是 34.149:凡是 containerd 的 443 且不是 10.1.10.3,都反查
# getent hosts <对端IP>
# getent hosts registry.gitlab.com
ING=/var/lib/containerd/io.containerd.content.v1.content/ingest
ls -la "$ING"
for d in "$ING"/*; do
[ -d "$d" ] || continue
echo "==== $(basename "$d") ===="
echo -n "ref="; cat "$d/ref"; echo
echo -n "total="; cat "$d/total"; echo
echo -n "startedat="; cat "$d/startedat"; echo
echo -n "updatedat="; cat "$d/updatedat"; echo
stat -c "data=%s mtime=%y" "$d/data"
done
ls -l /proc/$(pidof containerd)/fd | grep ingest || true
crictl images | grep toolbox

这次 ingest 目录名两边一样:b69bb7584d7ceeec51b9f1acf557c7cc62bbec595d676035a7a9c570b1f558d7(按 ref/digest 派生,不是随机到无法对照)。

ref=k8s.io/1/layer-sha256:bf390218420b5dcdeed2d425c9594b46bc91e2885f6beca227fb9147b55a2887
total=768735388
节点 ss ingest data / total
16.21 10.1.16.21:51968 → 34.149.22.116:443,containerd pid 3712737 fd 1343;ingest data 的 fd 也开着 上述 ref 383778816 B(366 MiB)/ 733 MiB,startedat=2026-09-11T22:00:35+08:00,下了 20+ 分钟
16.22 :57916 → 34.149.22.116:443,containerd pid 723673 fd 1357 同一 digest 466616320 B(445 MiB);ingest 约 21:46 开始
16.23 无此连接 已有 Harbor v19.3.2 de9db0f2559c3

34.149.22.116 反查 116.22.149.34.bc.googleusercontent.com,GitLab GCP。下次 GitLab.com 可能换 IP,不要把 34.149 写成永恒特征。

过 15 秒再 stat 一次 data。几乎不涨或只有几百 KB/s = 挂死(20 分钟下 366 MiB ≈ 0.3 MB/s)。Harbor 本地下完这层大约 10 秒。updatedat 这次从一开始就等于 startedat不要用它判断是否在下,看 data 的 size / mtime。

不要 rm -rf ingest/...:containerd 还开着 data 的 fd,删目录只会更脏。

16.21 的 containerd:max_concurrent_downloads = 3registry.mirrors 覆盖了 registry.k8s.iodocker.iogcr.ioquay.ioghcr.io 等,没有 harbor.cyxc.club,也没有把 Harbor 指到 GitLab。不是 mirror 把拉取拐走。

判定四条同时成立,就是这次这个问题:

  1. Harbor 对该 blob 200、快、没有 307
  2. 这台节点 ingest reflayer-sha256:bf390218420b…(别的节点有镜像不能代替)
  3. TCP 对端不是 10.1.10.3,反查是 GitLab/GCP
  4. 旧 Job 的 image 字段registry.gitlab.com/...,新 Pod 是 Harbor,同一 tag / 同一层 digest

不是这次的分支:

  • ingest 对端已经是 10.1.10.3 仍不涨 → 查 Harbor / RGW,不要掐 GitLab
  • 没有 ingest、镜像也没有 → kubelet 还没开始拉,或 CRI 挂了
  • 只有 Harbor 在 Pulling、events 和活对象里都没有 registry.gitlab.com → 另查(包括 Harbor 307
  • Harbor curl 也慢或 307 → 不要走节点 ss -K

根因

Harbor 对 bf390218420b200、大约 80 MiB/s 出层,没有 307。卡住的是节点上的 containerd:按 digest 存层,不按仓库名。同一层 digest 的 ingest 锁在每个节点自己的 content store里。旧 Job 先从 registry.gitlab.com 半截下载占住之后,同一节点上 Harbor 的拉取只能等。16.23 没有这条 GitLab.com ingest,所以能从 Harbor 拉完。不是全集群一把锁。

节点连 34.149.22.116:443,是因为 kubelet 的镜像引用就是 registry.gitlab.com/...,不是 Harbor proxy cache 把 GET 307 出去。项目 gitlab 作为 registry.gitlab.com 的 proxy cache,只负责层可以进仓。

Job 300ebb3 是哪一次写出来的

不是「CR 早就改成 Harbor、残留了一个很久以前的 Job」。它和 Harbor 的 toolbox ReplicaSet 是同一秒写出来的:

对象 创建时间 镜像
Job gitlab-migrations-300ebb3-e90-8-pre,UID e77696f3-a9bc-4cde-85b4-194d7fea165f 2026-09-11 13:46:15 UTC(21:46:15 CST) registry.gitlab.com/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2
ReplicaSet gitlab-toolbox-76f597b7f6(rev 4) 13:46:16Z(21:46:16) Harbor …/gitlab-toolbox-ce:v19.3.2

values 哈希 e90-8 写进 Job 名。大约 20 分钟后变成 e90-9,operator 另建 Job gitlab-migrations-a3aba68-e90-9-pre(Harbor),不会改已经存在的 300ebb3。Job 规格不可变:300ebb3 按 13:46:15 写入的 image 一直重试。Pod …-clqgl 在 16.21、…-qm644 在 16.22,所以两台都卡住。

活着的 CR 后来已经是 Harbor;generation=914:31:18Z / 14:31:19ZInitialized / Available。查当时写了什么:

Terminal window
kubectl -n gitlab get gitlab gitlab \
-o jsonpath='{.spec.chart.values.global.image.registry}{"\n"}'
kubectl -n gitlab get gitlab gitlab \
-o jsonpath='{.spec.chart.values.gitlab.migrations.image.repository}{"\n"}{.spec.chart.values.gitlab.toolbox.image.repository}{"\n"}'
kubectl -n gitlab get pods,jobs,deploy -o json \
| grep -oE 'image": "[^"]*toolbox-ce[^"]*"'

global.image.registry=harbor.cyxc.club/gitlab 不够。CNG Chart 的 repository 自带 registry.gitlab.com,只改 registry 前缀不会改掉已经写死的主机名。每个组件都要写完整 Harbor repository。见 gitlab.yaml 注释。

更早的 Job f354d9fe90-7)已经是 GitLab.com 的 v19.3.0,说明升级前节点本来就会直连 GitLab.com。16.21 本地还留着 registry.gitlab.com/.../gitlab-toolbox-ce:v19.3.0bc501b784b671,1.08GB),16.22 有 Harbor 的 v19.3.0。那是上一版,digest 不是 bf390218420b

CNG 层会共享,不限 toolbox:任何还在拉 registry.gitlab.com/gitlab-org/build/cng/... 的对象,都可能在所在节点锁住同一 digest。


处理

更稳妥:先删还在拉 GitLab.com 的 Job,再掐连接。否则 ImagePullBackOff 会立刻再连 GitLab,该节点同一 digest 又被占住。operator 可能把 Job 再建出来,删完再扫一遍。

当天实操是先 ss -K、没先删 Job。GitLab.com 拉取变成 connection abort,Job 随后自己没了。

Terminal window
kubectl -n gitlab get pods,jobs -o wide | grep -E '300ebb3|toolbox-ce'
kubectl -n gitlab get pods,jobs -o json | grep -F registry.gitlab.com
kubectl -n gitlab delete job gitlab-migrations-300ebb3-e90-8-pre --ignore-not-found
kubectl -n gitlab get pods,jobs -o json | grep -F registry.gitlab.com

然后每个卡住节点各掐一次,用该节点自己的 sport。不要整段 dst <gitlab-ip>,以免误杀同 IP 上其它 Google 连接。

当天用的是不带 sport 的:

Terminal window
ss -K dst 34.149.22.116 dport 443

21、22 各一次,能解开,但更粗。更稳:

Terminal window
ss -tnp | grep containerd | grep 34.149.22.116
# 这次 16.21 sport=51968,16.22 sport=57916
ss -K dst 34.149.22.116 dport 443 sport 51968

预期:

  • ingest 消失,或 data 不再涨
  • events:read tcp 10.1.16.21:51968->34.149.22.116:443: read: software caused connection abort(22 同理,sport 57916
  • containerd 改连 10.1.10.3:443

掐完后立刻看:16.21 ingest 已空,containerd 连着 10.1.10.3:443;16.22 仍有同一 ingest,但对端已经是 Harbor,data 涨到 613293248(585 MiB)。再过几十秒两边 ingest 都空了,可是 crictl images 还没列出 v19.3.2——kubelet 仍停在旧的 Pulling RPC 上。两台都补:

Terminal window
crictl pull harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2

16.21 22:22:59 开始,2 秒后 Image is up to date;16.22 约 12 秒。后台其实已经拉完。

ss -K 后 ingest 仍不放、containerd 无响应,再重启 containerd。控制面代价大,也去不掉根:GitLab.com 的 Job 还在,起来后可能再占 digest。

掐连接时其它 Pod 可能一次性 ErrImagePull。这次 gitlab-toolbox-76f597b7f6-9mwdz

Get "https://harbor.cyxc.club/v2/.../blobs/sha256:bf390218420b…": net/http: TLS handshake timeout

随后 Harbor 拉取应是 Successfully pulled / already present,不要当成仓坏了。


验证

Terminal window
crictl images | grep gitlab-toolbox-ce
# harbor.cyxc.club ... v19.3.2 de9db0f2559c3 1.08GB
ls /var/lib/containerd/io.containerd.content.v1.content/ingest # 空
ss -tnp | grep containerd | grep 34.149 # 无
kubectl -n gitlab get pods | grep -E 'toolbox|migrat' # Running / Completed

events:

Successfully pulled image "harbor.cyxc.club/.../gitlab-toolbox-ce:v19.3.2"
in 16m19.616s (16m19.616s including waiting). Image size: 1082636707 bytes.
Successfully pulled image "...toolbox-ce:v19.3.2"
in 22m31.002s (22m31.002s including waiting). Image size: 1082636707 bytes.

等待时间几乎全是 GitLab 那条连接。镜像本身从 Harbor 下只要十几秒。migrations / toolbox 从 PodInitializing 变成 1/1 Running


防再发

Terminal window
kubectl -n gitlab get events --sort-by=.lastTimestamp | grep -F registry.gitlab.com
kubectl -n gitlab get pods,jobs,deploy,sts -o json | grep -F registry.gitlab.com

活对象应全部是 Harbor。看到 GitLab.com 的 CNG 就删对应 Job,并确认 operator 没有立刻重建。gitlab.yaml 里每个组件都要写完整 Harbor 路径,toolbox / migrations 现在是:

harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce

附录:排查链路和最短路径

现象:toolbox / migrations 长时间 PodInitializing,events 只有 Pulling
├─ 1. 拉的是哪个仓库? events / describe / Pod .image
│ 两个仓库同时 Pulling 同一 tag → 可能抢 digest(按节点)
├─ 2. Harbor 这层还能不能出? curl blob,禁止 follow 307
│ 200 且快 → 仓、Traefik、RGW、HTTP/2 都排除
│ 307 到 gitlab.com → 才是 proxy cache 回源
│ 超时/EOF → 才查 Traefik / registry / RGW
├─ 3. 节点在跟谁传、卡哪一层? ss + ingest/ref + ingest/data
│ 对端不是 10.1.10.3 + ref=bf390218420b + data 几乎不涨
│ → 这台节点上的半截 GitLab 下载
│ 对端已是 10.1.10.3 仍不涨 → 才回头查 Harbor
├─ 4. 为何会去 GitLab.com? 旧 Job 的 image 字段和创建时间,不是 ss 猜的
│ 300ebb3 13:46:15Z = registry.gitlab.com;1 秒后 toolbox RS = Harbor
│ 同一层 digest → 这台节点 ingest 一把锁
└─ 5. 处理并验证 先删 GitLab.com Job,再 ss -K,再 crictl pull

查过但排除:

查了什么 结果 排除
本机 docker pull Get https://harbor.cyxc.club/v2/: EOF Docker daemon 代理
Harbor HEAD/GET/Range(含 512MiB 附近) 200/206,无 Location 层缺失、RGW 空洞、Harbor 307
HTTP/1.1 与 HTTP/2 整层 约 9s、~80 MiB/s Traefik/HTTP/2 卡大层
卡住节点抽 16MiB ~0.5s、~30 MiB/s 「节点到 Harbor 不通」
Traefik timeout 600s 默认 60s 切连接
core proxy cache 打 arm64 manifest 和这层无关 不要绑到 bf390218420b
registry blob unknown 9c1e19b0… 另一块 digest 不是这层
registry.mirrors 没有 Harbor 不是 mirror 到 GitLab
max_concurrent_downloads=3 默认值 不是原因
重启 containerd 未做;ss -K 已解开 不是必须

最短路径:

  1. describe / events:主容器长时间只有 Pulling;有没有 registry.gitlab.com 和 Harbor 同时拉 toolbox(含已删除 Pod);GitLab.com 的 Pod 落在哪几台;Job 的 creationTimestamp
  2. 卡住节点:getent hosts harbor.cyxc.club10.1.10.3ss 里 containerd 的 443 对端是不是 Harbor(这次是 34.149.22.116,Recv-Q/Send-Q 是否为 0;IP 会变,要反查)
  3. ingest/*/ref 是不是 bf390218420b,看 data 的 size 是否几乎不涨(不要看 updatedat
  4. 卡住节点上 curl --max-redirs 0 Harbor 该 blob:200、快、无 307
  5. 还在的 GitLab.com Job/Pod 先删掉,再确认没被 operator 重建
  6. 每个卡住节点:ss -K dst <对端IP> dport 443 sport <该节点 sport>
  7. crictl pull harbor.cyxc.club/gitlab/gitlab-org/build/cng/gitlab-toolbox-ce:v19.3.2
  8. Pod Running,ingest 空,不再连 GitLab GCP

附录:amd64 30 层

config sha256:de9db0f2559c3ccfa4690b2ca4bea58ab76a6cfaf5516766b3ed9c58be43709a。层压缩合计 1082618030 B。卡的是 17。

00 sha256:a8ac7f6c67abc236e4c745052c404112b8fab6fe8ac3a329d1ef3b867ad67c71 28232655
01 sha256:a29cbbf324724d8211418aac5b65fc07f5db5543af72ff82687007a3948bcc63 7156248
02 sha256:188663d35da33221b599e7b3235bedd857161ecdb0e98ce3531c1acbaa38193d 1268
03 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 32
04 sha256:1f1060c1e3b2c4bdd378b309265c4abcd9e5115bf55364ab9a1884a41b71f16f 29055560
05 sha256:fda767dcea1b8975a95916b2a8228f06f4d9ad62e86ef6c86621511e2957ba93 1953485
06 sha256:9bd288a93092ae1002f0897df086f3444ab87116e5568230cb15dea7aa7f78ee 12720354
07 sha256:55914a128bbf3e434d6e158eb7861a370855724d452b0d0dd30406392ceb5b8a 5060
08 sha256:77ce5c68db320603b1e94646350cb9ea02d4ac5095e0aa1d29cb8447610a05e1 39209755
09 sha256:c626ceac14b7e679dec0825c595fca7e7dd8a63567a6847281a9754d9d991fbb 28031057
10 sha256:33014e15442a13d5cf531b4a2b17e31ec11a5d4f09d453bc25f9cf82aa0be1c5 1520328
11 sha256:6588bb78f1c6a8cdec17b0bae901785adafab86cc7e15e7a6614cdca25d7291f 318058
12 sha256:1c63f8c5fb002c0c366a080d746ab921519e2efb67fd7b7f9f8bc6f8e915c0fb 526719
13 sha256:a2ad6535aeab354bac48304dc630c0100e2247e2052b929af78626dfcfa2a472 3595658
14 sha256:a4a2264495378446a5bd77749d7c26633e33791fa8d14ebf04f41a16be5164f2 5509053
15 sha256:60880a3b740ee5b0df223b0e773795a734592149d2afbec31f48d7b4d3b8e51b 21508691
16 sha256:ac05878049d35074c8f8f6a8765b0befecccd71e9ada559ada045ea89116edfa 3359
17 sha256:bf390218420b5dcdeed2d425c9594b46bc91e2885f6beca227fb9147b55a2887 768735388
18 sha256:4b2390aba4b7e61e0942baa45280b5feecae8c764b164d117547be5fbe881da7 225
19 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 32
20 sha256:74777c880bc08df616187fedc77d1dff3576c6603d67afcec436d2ad9e267d7f 1230
21 sha256:01ddbc40c96e17b284c39e0d5a590506ddc47f0b337ea953f08a41a4860c1c39 8411
22 sha256:94874a0070a508da42eb59e278f9ce743e9e5b93441b68306825bd04738a94f9 86535
23 sha256:0868632af4ecff87675447a349fb5e2b617f8c2ae01e713edce7bff75958fad3 74804934
24 sha256:6c60b87d0dbb0fcfe49957a77126550f67e1a7b77c9c73cde2f47eb8e1f33e4a 275544
25 sha256:f467a892639e164e1bf95d7e4e59d4936ea4826437b6775d35ad24a486ece345 3687748
26 sha256:96fdc535a1aee88164b0034c20e124ed171b5d110efa37a2a36e3ef23fbe7fad 31790733
27 sha256:9679f988225583408626eb598e75311c12a441146e020dcef5b594b419d01b45 23869343
28 sha256:66f36859f0cfd2ec19e69ad7045092d21ab4a15e3798b831a8f9a11a7222d736 7230
29 sha256:f4dbd993078ebaecd22a908cd0d0b5d1822161fe29cf31e47f39633cc10b90c9 3337

预拉其它镜像(同一脚本,仅作对照):operator 54.9 MiB / 37.2s;certificates 63.3 MiB / 163.9s;gitaly 456.5 MiB / 102.4s;workhorse 540.4 MiB / 540.8s;webservice 950.9 MiB / 519.0s;sidekiq 1022.4 MiB / 562.0s。sidekiq 也接近 1 GiB,当天没有逐层核对是否与 toolbox 共享 bf390218420b。仍应假定:任何 GitLab.com 的 CNG 拉取都可能在所在节点锁住大层。