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

相关推荐
源代码•宸21 小时前
goframe框架签到系统项目(BITFIELD 命令详解、Redis Key 设计、goframe 框架教程、安装MySQL)
开发语言·数据库·经验分享·redis·后端·mysql·golang
原神启动11 天前
Docker 场景化作业:生产环境容器操作实训
运维·docker·容器
呼啦啦呼啦啦啦啦啦啦1 天前
docker制作镜像的两种方式(保姆级教学)
运维·docker·容器
普通网友1 天前
Bash语言的图算法
开发语言·后端·golang
雨岚霏1 天前
Bash语言的数据库编程
开发语言·后端·golang
木风小助理1 天前
PostgreSQL 的范式跃迁:从关系型数据库到统一数据平台
服务器·云原生·kubernetes
qq_455760851 天前
docker - 网络
运维·docker·容器
bybitq1 天前
Go函数闭包实战-复用函数
ios·golang·xcode
m0_488777651 天前
Docker容器技术场景化操作实战及网络模式部署
运维·docker·容器·网络模式
2501_939909051 天前
Docker
运维·docker·容器