容器-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

相关推荐
风生u1 小时前
Go中的反射
golang·反射
天命码喽c1 小时前
Docker-compose部署GraphRAG-2.7.0
运维·docker·容器
T.O.P_KING2 小时前
Common Go Mistakes(IV 字符串)
开发语言·后端·golang
你的坚持终将美好,3 小时前
Docker 中一起启动多个容器脚本
docker·容器
像风一样自由20203 小时前
Docker 与 Docker Compose:从零开始的容器化之旅
运维·docker·容器
北珣.3 小时前
docker镜像操作
运维·docker·容器·镜像
Hello.Reader3 小时前
用纯 Go 实现一个 AES-128 加密 m3u8 视频下载器(不依赖 ffmpeg)
golang·ffmpeg·音视频·m3u8
Sally_xy3 小时前
安装 Docker
java·docker·容器
❥ღ Komo·4 小时前
K8S Deployment 详解与实战指南
docker·容器·kubernetes