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

相关推荐
Sheffield1 天前
Alpine是什么,为什么是Docker首选?
linux·docker·容器
可观测性用观测云4 天前
云原生网关 Ingress-Nginx 链路追踪实战:OpenTelemetry 采集与观测云集成方案
nginx·kubernetes
蝎子莱莱爱打怪6 天前
GitLab CI/CD + Docker Registry + K8s 部署完整实战指南
后端·docker·kubernetes
蝎子莱莱爱打怪9 天前
Centos7中一键安装K8s集群以及Rancher安装记录
运维·后端·kubernetes
崔小汤呀9 天前
Docker部署Nacos
docker·容器
缓解AI焦虑9 天前
Docker + K8s 部署大模型推理服务:资源划分与多实例调度
docker·容器
花酒锄作田9 天前
Gin 框架中的规范响应格式设计与实现
golang·gin
1candobetter10 天前
Docker Compose Build 与 Up 的区别:什么时候必须重建镜像
docker·容器·eureka
阿里云云原生10 天前
Kubernetes 官方再出公告,强调立即迁移 Ingress NGINX
kubernetes
至此流年莫相忘10 天前
Kubernetes实战篇之配置与存储
云原生·容器·kubernetes