容器-PUSH镜像卡住问题排查

背景:

上文提到刚搭建了docker-compose 部署了harbor 镜像仓库v2.12.4,镜像最终存储到远端S3上,但是本地 docker push上传镜像却在push完之后一直卡住了。。。

复制代码
# docker push harbor.domain.net/goharbor/harbor-exporter:v2.12.4 
The push refers to repository [harbor.domain.net/goharbor/harbor-exporter]
82ad754be5b8: Pushing [==================================================>]  4.096kB
5f70bf18a086: Pushing  1.024kB
41f53763f274: Pushing  1.536kB
3690ac561010: Pushing [==================================================>]     27MB
167b50cbc9a5: Pushing [==================================================>]  4.145MB
544b14d8a201: Waiting 
4724408ab3be: Waiting 
d6d0586ce802: Waiting 
排查:

现象:docker login以及harbor 界面使用是没问题的,只是push镜像有问题。

1. 排查前先理清镜像上传的流程:
复制代码
docker client
  ↓
nginx(proxy)
  ↓
core(harbor-core)
  ↓
registry(harbor-registry)
  ↓
S3 backend (对象存储)
2. 分析问题

​ 异常第一反应就是看日志,所以,想看下core以及registry是否有异常,通过docker logs看即可,但是看log没有什么异常信息。

​ 因为push并无任何报错,client也不提示任何信息,harbor相关服务也没有错误日志,所以怀疑是网络问题,而卡住所以怀疑是MTU问题。

​ 我们知道,TCP和MTU一个工作在三层一个是二层的,所以TCP不知道MTU的问题,它只知道包发出去了但是没有ACK回来,按照TCP的规范,TCP会指数退避重试,每次超时重传间隔会越来越长,只要连接还在,应用层就不会报错,TCP没有告诉应用层连接不可用,所以应用层只能"挂着"。

可以在宿主机抓包,能够抓到docker0给容器了需要分包的icmp报文

复制代码
# tcpdump -nnee -i any icmp and 'icmp[0]=3 and icmp[1]=4'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
17:19:26.356337 Out 02:42:bd:a8:90:1c ethertype IPv4 (0x0800), length 592: 172.18.0.1 > 172.18.0.8: ICMP 10.118.60.33 unreachable - need to frag (mtu 1450), length 556
17:19:26.356348 Out 02:42:bd:a8:90:1c ethertype IPv4 (0x0800), length 592: 172.18.0.1 > 172.18.0.8: ICMP 10.118.60.33 unreachable - need to frag (mtu 1450), length 556
17:20:21.948816 Out 02:42:bd:a8:90:1c ethertype IPv4 (0x0800), length 592: 172.18.0.1 > 172.18.0.7: ICMP 10.224.144.23 unreachable - need to frag (mtu 1450), length 556

所以问题的原因是在上传镜像大blob时,因为容器MTU 1500并且有DF(don't fragment) 不能分片标志位,而docker0 MTU 1450,导致包发不出去,同时tcp一直等待,虽然下游返回了需要分片,可能和go语言自身net/http包对TLS的处理有BUG吧,在后续MTU变小后即使收到了ICMP也并会调整当前连接,所以导致一直卡住。

3. 解决问题

将容器的网卡mtu改成和宿主机eth0一样的mtu,因为宿主机是虚机,虚机mtu是1450,所以改容器的mtu。

更改harbor的docker-compose.yml

复制代码
networks:
  harbor:
    driver: bridge
    driver_opts:
      com.docker.network.driver.mtu: 1450

长期来说,docker网络的mtu要与宿主机保持一致。

#/etc/docker/daemon.json

{ "mtu": 1450 }

restart docker

相关推荐
张忠琳4 小时前
【client-go v0.36.1】(store Part 3)Store 超深度分析 — 集成模式、完整数据流、不变量、与 DeltaFIFO 协作
云原生·kubernetes·informer·store·client-go
赵渝强老师6 小时前
【赵渝强老师】Kubernetes(K8s)中的金丝雀升级
linux·docker·云原生·容器·kubernetes
晨曦中的暮雨6 小时前
Golang速通(Javaer版)
java·开发语言·后端·golang
鹤落晴春7 小时前
【K8s】配置存储卷
云原生·容器·kubernetes
张忠琳8 小时前
【client-go v0.36.1】(DeltaFIFO Part 1)DeltaFIFO 超深度分析 — 模块定位、类结构、接口层次、构造与初始化
云原生·kubernetes·deltafifo·informer·client-go
原来是猿9 小时前
Docker 【 技术架构(1)】
docker·容器·架构
ba_pi9 小时前
k8s删除pod
linux·容器·kubernetes
木雷坞10 小时前
Qdrant Docker 部署教程:数据卷、API Key 和集合初始化
运维·docker·容器·知识图谱
张忠琳12 小时前
【client-go v0.36.1】tools/cache 深度分析(下篇)— RealFIFO 深度、集成架构、生命周期、设计模式总结
云原生·kubernetes·cache·informer·client-go
codeejun12 小时前
每日一Go-76(架构篇)|多集群部署 / 容灾 / Failover / Backup / 热迁移
开发语言·架构·golang