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

相关推荐
运维开发故事3 天前
基于 Arthas 的多集群在线诊断系统设计与实现
kubernetes
Patrick_Wilson5 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
探索云原生5 天前
K8s 1.36 这个 GA 特性,把 initContainer 拉模型的 hack 干掉了
ai·云原生·kubernetes
云恒要逆袭5 天前
运行你的第一个Docker容器
后端·docker·容器
Java之美6 天前
一次k8s升级引发的DevicePlugin注册失败
云原生·kubernetes
程序员老赵7 天前
10 分钟部署 OpenCode:Docker 一键安装,浏览器打开就能用 AI 写代码(附完整命令与排错)
docker·容器·ai编程
武子康10 天前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
何以解忧,唯有..13 天前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
2601_9618752413 天前
决战申论100题2026|最新|范文
linux·容器·centos·debian·ssh·fabric·vagrant