首页 > 其他分享 >解决国产系统 Docker 拉取大镜像卡顿之谜

解决国产系统 Docker 拉取大镜像卡顿之谜

时间:2024-05-08 16:26:02浏览次数:21  
标签:err unpigz 拉取 Download 镜像 Docker docker 卡顿

今天解决了客户 arm64 机器上 docker pull 大镜像卡住的问题。

由来

同事让我帮忙解决客户现场 Docker 镜像无法拉取的问题,故障如下会一直卡住:

  1.   $ docker pull xxx:5000/xxxx
  2.   xxx: Pulling from xxx/xxxxxx
  3.   7c0b344a74c2: Extracting [>                                                  ]  294.9kB/26.66MB
  4.   7c0b344a74c2: Download complete
  5.   e53ed7fd3110: Download complete
  6.   d2cae797bc79: Download complete
  7.   ec3ddc176f08: Download complete
  8.   2969517e196e: Download complete
  9.   097fa64722e8: Download complete
  10.   1dde4ca01a5a: Download complete

离线文件 load -i 后,打上 tag 推送到镜像仓库,然后本地删除这个镜像,然后拉取还是像上面这样卡住,部分小镜像拉取没问题,所以不可能是 docker data-root 的挂载 option 影响。环境信息如下:

  1.   $ docker info
  2.   ...
  3.    Server Version: 19.03.15
  4.    Storage Driver: overlay2
  5.     Backing Filesystem: extfs
  6.     Supports d_type: true
  7.     Native Overlay Diff: true
  8.    Logging Driver: json-file
  9.    Cgroup Driver: cgroupfs
  10.    Plugins:
  11.     Volume: local
  12.     Network: bridge host ipvlan macvlan null overlay
  13.     Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
  14.    Swarm: inactive
  15.    Runtimes: runc
  16.    Default Runtime: runc
  17.    Init Binary: docker-init
  18.    containerd version: ea765aba0d05254012b0b9e595e995c09186427f
  19.    runc version: v1.0.0-0-g84113eef
  20.    init version: fec3683
  21.    Security Options:
  22.     seccomp
  23.      Profile: default
  24.    Kernel Version: 4.19.90-2211.5.0.0178.22.uel20.aarch64
  25.    Operating System: UnionTech OS Server 20
  26.    OSType: linux
  27.    Architecture: aarch64
  28.    CPUs: 24
  29.    Total Memory: 94.56GiB
  30.    Name: host-xxxx
  31.    ID: RTQS:5TXE:5T3S:YW7X:OHPK:FZ7D:7EHD:DH5Z:JNBV:FVXS:24FA:EIVS
  32.    Docker Root Dir: /data/kube/docker
  33.    Debug Mode: true
  34.     File Descriptors: 29
  35.     Goroutines: 46
  36.     System Time: 2023-04-12T16:10:25.33362426+08:00
  37.   $ uname -a
  38.   Linux host-x 4.19.90-2211.5.0.0178.22.uel20.aarch64 #1 SMP Thu Nov 24 10:33:07 CST 2022 aarch64 aarch64 aarch64 GNU/Linux
  39.   $ cat /etc/os-release
  40.   PRETTY_NAME="UnionTech OS Server 20"
  41.   NAME="UnionTech OS Server 20"
  42.   VERSION_ID="20"
  43.   VERSION="20"
  44.   ID=uos
  45.   HOME_URL="https://www.chinauos.com/"
  46.   BUG_REPORT_URL="https://bbs.chinauos.com/"
  47.   VERSION_CODENAME=fuyu
  48.   PLATFORM_ID="platform:uel20"

排查

卡住的过程中,另外开一个 ssh top 发现进程 unpigz 占用较高,利用其 pid 查看了一些信息:

  1.   $ pstree -sp 1170083
  2.   systemd(1)───dockerd(1169795)───unpigz(1170083)─┬─{unpigz}(1170084)
  3.                                                   ├─{unpigz}(1170086)
  4.                                                   └─{unpigz}(1170087)

发现这个进程是 Docker 调用的,strace 只能看到卡住,kill 了 unpigz 后,卡住的 pull 开始报错了:

failed to register layer: Error processing tar file(exit status 1): unexpected EOF
 

Docker 的镜像每层 layer 实际是 tar,pull 时会下载 tar 包然后解压,这个看着是解压相关的逻辑出现了问题。在 Docker 源码里搜索 Error processing tar file 后找到:

  1.   // https://github.com/moby/moby/blob/v19.03.15/pkg/chrootarchive/archive_unix.go#L90-L116
  2.    cmd := reexec.Command("docker-untar", dest, root)
  3.     ...
  4.    if err := cmd.Wait(); err != nil {
  5.     // when `xz -d -c -q | docker-untar ...` failed on docker-untar side,
  6.     // we need to exhaust `xz`'s output, otherwise the `xz` side will be
  7.     // pending on write pipe forever
  8.     io.Copy(ioutil.Discard, decompressedArchive)
  9.    
  10.     return fmt.Errorf("Error processing tar file(%v): %s", err, output)
  11.    }
  12.    return nil

看注释里的xz -d -c -q | docker-untar ...,与 unpigz 的 cmdline 和一个卡住的 docker-untar 进程相符:

  1.   $ xargs -0 < /proc/1170083/cmdline
  2.   /usr/bin/unpigz -d -c
  3.   $ ps aux | grep docker-unta[r]
  4.   root     1164788  0.0  0.0 1491008 39488 pts/2   Sl+  15:21   0:00 docker-untar / /data/kube/docker/overlay2/546b7b992b53b243450807b8150c4a1905e93afae604da69a21bbaaf443f178e/diff

看来是 exec 调用 unpigz 解压管道给 reexec 注册的 docker-untar,而上面的 unpigz 进程树显示是 docker 默认调用的而非 xz。搜索后发现,unpigz 是一个在 gz 格式处理上比 gzip 更快的实现。既然 Docker 是 exec 调用的 unpigz,那就在源码里搜索它看看:

  1.   // https://github.com/moby/moby/blob/v19.03.15/pkg/archive/archive.go#L32-L39
  2.   func init() {
  3.    if path, err := exec.LookPath("unpigz"); err != nil {
  4.     logrus.Debug("unpigz binary not found in PATH, falling back to go gzip library")
  5.    } else {
  6.     logrus.Debugf("Using unpigz binary found at path %s", path)
  7.     unpigzPath = path
  8.    }
  9.   }

往下翻看,发现 unpigzPath 的 exec 调用逻辑:

  1.   // https://github.com/moby/moby/blob/v19.03.15/pkg/archive/archive.go#L160-L174
  2.   func gzDecompress(ctx context.Context, buf io.Reader) (io.ReadCloser, error) {
  3.    if unpigzPath == "" {
  4.     return gzip.NewReader(buf)
  5.    }
  6.    
  7.    disablePigzEnv := os.Getenv("MOBY_DISABLE_PIGZ")
  8.    if disablePigzEnv != "" {
  9.     if disablePigz, err := strconv.ParseBool(disablePigzEnv); err != nil {
  10.      return nil, err
  11.     } else if disablePigz {
  12.      return gzip.NewReader(buf)
  13.     }
  14.    }
  15.    
  16.    return cmdStream(exec.CommandContext(ctx, unpigzPath, "-d", "-c"), buf)
  17.   }

现场 unpigz 版本:

  1.   $ rpm -qf /bin/unpigz
  2.   pigz-2.4-7.uel20.01.aarch64
  3.   $ rpm -V pigz
  4.   # -V 查看包也没被修改

注意看其中有个 env 设置不使用 PIGZ 而是使用 gzip,然后启动 Docker Daemon 时设置这个 env 就可以拉取镜像了:

  1.   $ systemctl stop docker
  2.   # 临时命令行前台 debug 启动下看看是没问题的
  3.   $ MOBY_DISABLE_PIGZ=true dockerd --debug

后续

UOS 这个系统需要授权才能使用 yum 安装升级,访问 repo 里的 url 会报错 401,让客户联系 UOS 厂商升级 pigz 包发现是最新的版本,只能使用 MOBY_DISABLE_PIGZ 环境变量回退到 gz 了。

e92f2a06f0482bbd1e02d5b24db440ba.gif

ef12f9fd8f26d59fb7c57b73bf676766.png

你可能还喜欢

点击下方图片即可阅读

 

尝试用 ChatGPT 完整的实现一个 Serverless 后端工程

2023-04-19

0e41e3b9cafba1434221b2a413f06c36.jpeg

 

Laf Assistant:云开发从未如此爽快!

2023-04-12

607fb8eed8c787ca0af46e7a620f639f.jpeg

 

AI 绘画神还原王维的《鸟鸣涧》

2023-04-11

ff828caf4274a01a5a28ad56e738d6e4.jpeg

 

ChatGPT 与 Midjourney 强强联手,让先秦阿房宫重现辉煌!

2023-04-06

b110c197e83f2bf724e4d2206f9ebed0.jpeg

63d3d3266aee9184f1325f0dbf9d0fba.gif

云原生是一种信仰 

标签:err,unpigz,拉取,Download,镜像,Docker,docker,卡顿
From: https://www.cnblogs.com/fanwenyan/p/18180100

相关文章

  • Docker 部署 Redis
    获取镜像#拉取镜像此处我们拉取的是官方最新镜像,其它版本可以去DockerHub查询[root@VM-24-9-centos~]#dockerpullredis:7.2创建挂载目录并复制相关文件##创建挂载目录[root@VM-0-17-centos~]#mkdir-pdata/redis/{conf,data}##切换到conf目录并下载配置文件和......
  • docker安装redis
    因为经常要自己弄服务器,有的命令用完就忘了。现在记一下拉取镜像dockerpullredis##创建目录mkdir-p/opt/docker/redis/confmkdir-p/opt/docker/redis/data #生成假的容器dockerrun-di--name=myredisredis#复制配置文件到宿主机dockercpmymysql:/etc/red......
  • docker - [15] springboot微服务打包docker镜像
    步骤:1、构建Springboot项目2、打包应用3、编写dockerfile4、构建docker镜像5、发布运行   一、构建Springboot项目(1)创建一个SpringBoot(以下这种方式对jdk版本有要求,可以创建一个Maven项目使用jdk8)(2)使用的SpringBoot版本是3.x,所以要求jdk17+(3)修改SpringBoot和jd......
  • [转]docker访问宿主机 host.docker.internal 域名不生效的问题
    原文地址:docker网络问题host.docker.internal不生效?-SegmentFault思否host.docker.internal是一个开发功能,只在DockerDesktop有效。你用的是DockerDesktop吗?(Linux下一般都不是)https://docs.docker.com/deskt...ThehosthasachangingIPaddress(ornoneif......
  • docker部署kafka服务
    dockerrun-d--namekafka--hostnamekafka-server\--log-optmax-size=200m\--log-optmax-file=1\--restart=always\-p9092:9092\--memory1024m\-eKAFKA_CFG_LOG_RETENTION_MS=60000\-eKAFKA_CFG_MAX_REQUEST_SIZE......
  • 使用 Docker 部署 TaleBook 私人书籍管理系统
    1)项目介绍GitHub:https://github.com/talebook/talebookTalebook是一个简洁但强大的私人书籍管理系统。它基于Calibre项目构建,具备书籍管理、在线阅读与推送、用户管理、SSO登录、从百度/豆瓣拉取书籍信息等功能。友情提醒:个人是不允许进行在线出版的,维护公开的书籍网站......
  • 021Dockerfile相关
    一、dockerhistory镜像层文件确认方法#(1)问:如何查询dockerfile里的ADDfile:a0a9df396dd400a83cc437cba4830851b18457de79db5955704378c6d206b9a1in/usr/local/java/实际文件file后的id?ADDfile:a0a9df396dd400a83cc437cba4830851b18457de79db5955704378c6d206b9a1i......
  • docker离线导入镜像
    在有网络的服务器上操作1、下载docker镜像dockerpull<image_name>:<tag>2、保存下载的docker镜像为压缩文件dockersave-oimage_file.tar<image_name>:<tag>3、将压缩文件传输到目标服务器scpimage_file.taruser@target_server_ip:/path/to/destination_folder......
  • 一个小工具识别哪个docker占用gpu
    我们经常会为了组内谁在占用某块gpu卡而不使用烦恼,通过简单的代码就能快速识别到这块卡上面的进程是哪个容器的。下面的代码会给出如下图这样的结果#!/miniconda3/bin/python#-*-coding:utf-8-*-importpsutilimportsubprocessasspdefpre():ans=sp.che......
  • Oracle update语句引起大量业务卡顿
    记一次update语句引起大量业务卡顿分析处理过程,聊聊我的思路。技术人人都可以磨炼,但处理问题的思路和角度各有不同,希望这篇文章可以抛砖引玉。以一个例子为切入点一、问题背景某业务模块反馈最近出现过几次业务卡顿,数据库中定位到有几个insertinto语句的gc等待比较严重,虽然......