前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >解决国产系统 Docker 拉取大镜像卡顿之谜

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

作者头像
米开朗基杨
发布于 2023-09-09 10:44:43
发布于 2023-09-09 10:44:43
1.6K00
代码可运行
举报
文章被收录于专栏:云原生实验室云原生实验室
运行总次数:0
代码可运行

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

由来

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ docker pull xxx:5000/xxxx
xxx: Pulling from xxx/xxxxxx
7c0b344a74c2: Extracting [>                                                  ]  294.9kB/26.66MB
7c0b344a74c2: Download complete
e53ed7fd3110: Download complete
d2cae797bc79: Download complete
ec3ddc176f08: Download complete
2969517e196e: Download complete
097fa64722e8: Download complete
1dde4ca01a5a: Download complete

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ docker info
...
 Server Version: 19.03.15
 Storage Driver: overlay2
  Backing Filesystem: extfs
  Supports d_type: true
  Native Overlay Diff: true
 Logging Driver: json-file
 Cgroup Driver: cgroupfs
 Plugins:
  Volume: local
  Network: bridge host ipvlan macvlan null overlay
  Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
 Swarm: inactive
 Runtimes: runc
 Default Runtime: runc
 Init Binary: docker-init
 containerd version: ea765aba0d05254012b0b9e595e995c09186427f
 runc version: v1.0.0-0-g84113eef
 init version: fec3683
 Security Options:
  seccomp
   Profile: default
 Kernel Version: 4.19.90-2211.5.0.0178.22.uel20.aarch64
 Operating System: UnionTech OS Server 20
 OSType: linux
 Architecture: aarch64
 CPUs: 24
 Total Memory: 94.56GiB
 Name: host-xxxx
 ID: RTQS:5TXE:5T3S:YW7X:OHPK:FZ7D:7EHD:DH5Z:JNBV:FVXS:24FA:EIVS
 Docker Root Dir: /data/kube/docker
 Debug Mode: true
  File Descriptors: 29
  Goroutines: 46
  System Time: 2023-04-12T16:10:25.33362426+08:00
$ uname -a
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
$ cat /etc/os-release
PRETTY_NAME="UnionTech OS Server 20"
NAME="UnionTech OS Server 20"
VERSION_ID="20"
VERSION="20"
ID=uos
HOME_URL="https://www.chinauos.com/"
BUG_REPORT_URL="https://bbs.chinauos.com/"
VERSION_CODENAME=fuyu
PLATFORM_ID="platform:uel20"

排查

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ pstree -sp 1170083
systemd(1)───dockerd(1169795)───unpigz(1170083)─┬─{unpigz}(1170084)
                                                ├─{unpigz}(1170086)
                                                └─{unpigz}(1170087)

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
failed to register layer: Error processing tar file(exit status 1): unexpected EOF

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// https://github.com/moby/moby/blob/v19.03.15/pkg/chrootarchive/archive_unix.go#L90-L116
 cmd := reexec.Command("docker-untar", dest, root)
  ...
 if err := cmd.Wait(); err != nil {
  // when `xz -d -c -q | docker-untar ...` failed on docker-untar side,
  // we need to exhaust `xz`'s output, otherwise the `xz` side will be
  // pending on write pipe forever
  io.Copy(ioutil.Discard, decompressedArchive)

  return fmt.Errorf("Error processing tar file(%v): %s", err, output)
 }
 return nil

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ xargs -0 < /proc/1170083/cmdline
/usr/bin/unpigz -d -c
$ ps aux | grep docker-unta[r]
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,那就在源码里搜索它看看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// https://github.com/moby/moby/blob/v19.03.15/pkg/archive/archive.go#L32-L39
func init() {
 if path, err := exec.LookPath("unpigz"); err != nil {
  logrus.Debug("unpigz binary not found in PATH, falling back to go gzip library")
 } else {
  logrus.Debugf("Using unpigz binary found at path %s", path)
  unpigzPath = path
 }
}

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// https://github.com/moby/moby/blob/v19.03.15/pkg/archive/archive.go#L160-L174
func gzDecompress(ctx context.Context, buf io.Reader) (io.ReadCloser, error) {
 if unpigzPath == "" {
  return gzip.NewReader(buf)
 }

 disablePigzEnv := os.Getenv("MOBY_DISABLE_PIGZ")
 if disablePigzEnv != "" {
  if disablePigz, err := strconv.ParseBool(disablePigzEnv); err != nil {
   return nil, err
  } else if disablePigz {
   return gzip.NewReader(buf)
  }
 }

 return cmdStream(exec.CommandContext(ctx, unpigzPath, "-d", "-c"), buf)
}

现场 unpigz 版本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ rpm -qf /bin/unpigz
pigz-2.4-7.uel20.01.aarch64
$ rpm -V pigz
# -V 查看包也没被修改

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ systemctl stop docker
# 临时命令行前台 debug 启动下看看是没问题的
$ MOBY_DISABLE_PIGZ=true dockerd --debug

后续

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-04-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云原生实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
测试必会 | Docker 核心命令技能
attach; build; commit; cp; diff; export; images; exec;
louiezhou001
2020/04/21
6020
测试必会 | Docker 核心命令技能
万字长文:彻底搞懂容器镜像构建
这里我们先从宏观上对 Docker 有个大概的认识,它整体上是个 C/S 架构;我们平时使用的 docker 命令就是它的 CLI 客户端,而它的服务端是 dockerd 在 Linux 系统中,通常我们是使用 systemd 进行管理,所以我们可以使用 systemctl start docker 来启动服务。(但是请注意,dockerd 是否能运行与 systemd 并无任何关系,你可以像平时执行一个普通的二进制程序一样,直接通过 dockerd 来启动服务,注意需要 root 权限)
Jintao Zhang
2021/03/16
1.1K2
Docker 深入篇之 Build 原理
使用 Docker 时,最常用的命令无非是 docker container 和 docker image 相关的子命令,当然最初没有管理类命令(或者说分组)的时候,最常使用的命令也无非是 docker run docker commit docker build 和 docker images 这些。
Jintao Zhang
2018/10/10
2K0
Docker 加持的安卓手机:随身携带的知识库(一)
这篇文章聊聊,如何借助 Docker ,尝试将一台五年前的手机,构建成一个随身携带的、本地化的知识库。
soulteary
2024/05/03
7830
【Docker】MySQL 源码构建 Docker 镜像(基于 ARM 64 架构)
近期,笔者正推进公司 MySQL 适配 ARM 64 架构工作,由于一直使用 Docker Hub 上的官方镜像,所以第一时间在 Hub 上检索,却发现官方只为 MySQL 8.0 以上版本提供 ARM 64 镜像。
行者Sun
2024/09/02
6080
【Docker】MySQL 源码构建 Docker 镜像(基于 ARM 64 架构)
统信服务器操作系统V20 1070e 【dockerfile 构建镜像】
dockerFile 是一个文本文件,它包含了一系列的指令,这些指令用于自动化构建 docker 镜像的过程。docker 镜像是只读模板,可以用来创建 docker 容器的实例。dockerfile 使得开发者可以定义一个镜像的构建过程,而这个镜像可以被用来批量部署应用程序和服务。
Kevin song
2024/07/04
4880
统信服务器操作系统V20 1070e 【dockerfile 构建镜像】
Docker 加持的安卓手机:随身携带的知识库(一)
这篇文章聊聊,如何借助 Docker ,尝试将一台五年前的手机,构建成一个随身携带的、本地化的知识库。
soulteary
2024/05/11
3330
Docker 加持的安卓手机:随身携带的知识库(一)
Docker镜像管理
从docker指定的仓库下载镜像到本地 用法: docker pull 镜像名称
星哥玩云
2022/09/15
4530
如何基于当前操作系统构建 Docker 系统基础镜像
不必太纠结于当下,也不必太忧虑未来,当你经历过一些事情的时候,眼前的风景已经和从前不一样了。——村上春树
山河已无恙
2024/02/26
9180
如何基于当前操作系统构建 Docker 系统基础镜像
Docker容器镜像仓库存储原理(前世今身)与搬运技巧
在深入学习镜像之前我们需要知道镜像是如何(炼制/搓)成的(等同于构建镜像),当然是通过我们DockerFile一条条指令为镜像生成每一层,按照执行顺序镜像文件系统复写封装从下到上;
全栈工程师修炼指南
2022/09/29
3.5K0
Docker容器镜像仓库存储原理(前世今身)与搬运技巧
使用 Docker Buildx 构建多种系统架构镜像
Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持 Moby BuildKit 提供的功能。提供了与 docker build 相同的用户体验,并增加了许多新功能。
没有故事的陈师傅
2021/09/09
1.7K0
统信服务器操作系统【docker 介绍及部署安装】
Docker是一个基于go语言开源的应用容器引擎,它允许开发者将应用及其依赖打包到一个可移植的容器中,然后发布到任何支持Docker的Linux或Windows操作系统上。Docker基于内核的轻量级虚拟化技术,使用沙箱机制,容器之间相互隔离。通过容器来打包应用、解耦应用和运行平台Docker 可以快速创建和删除容器,实现快速迭代,节约开发、测试及部署的时间。
Kevin song
2024/05/11
2.1K0
统信服务器操作系统【docker 介绍及部署安装】
一文搞定 Containerd 的使用
在学习 Containerd 之前我们有必要对 Docker 的发展历史做一个简单的回顾,因为这里面牵涉到的组件实战是有点多,有很多我们会经常听到,但是不清楚这些组件到底是干什么用的,比如 libcontainer、runc、containerd、CRI、OCI 等等。
CNCF
2021/08/26
11K0
一文搞定 Containerd 的使用
Docker基本命令
[root@localhost ~]# docker Usage: docker [OPTIONS] COMMAND A self-sufficient runtime for containers Options: --config string Location of client config files (default "/root/.docker") -D, --debug Enable debug mode -H, --host
红目香薰
2022/11/29
3550
Docker基本命令
Docker快速上手指北(一)【技术创作101训练营】
帮助文档的地址:https://docs.docker.com/engine/reference/commandline/docker/
yussuy
2020/09/23
4280
Docker快速上手指北(一)【技术创作101训练营】
麒麟系统V10 SP2 二进制部署Docker
docker服务部署会自动创建3种网络:bridge、host、none。
Kevin song
2022/11/19
1.9K0
申威(神/声)(SW)1621 + UOS 20 编译安装 Docker | 容器国产化适配
1.解压 runc 源码至 ~/go/src/github.com/opencontainers 目录;
宋天伦
2023/10/20
1.4K0
ARM架构麒麟系统下,使用docker部署安装LAMP环境
Kylin操作系统是一个中国自主知识产权操作系统,是国家高技术研究发展计划(863计划)的重大成果之一,是以国防科技大学为主导,与中软、联想等单位联合设计和开发的基于Linux的系统,可支持多种微处理器和多种计算机体系结构,具有高性能、高可用性和高安全性,并与Linux应用二进制兼容的国产中文服务器操作系统。
KunkkaWu
2024/06/03
7030
Docker | 常用命令——排错很有帮助
众所周知,docker 排查问题相较而言是困难的。因此,熟知一些常用命令对我们快速的排查定位问题是非常有帮助的。下面让我们一起来学习一下吧👇 1、显示docker的系统信息 docker info [root@xiao docker]# docker info Client: Context: default Debug Mode: false Plugins: app: Docker App (Docker Inc., v0.9.1-beta3) buildx: Build wi
甜点cc
2022/11/16
4240
Docker | 常用命令——排错很有帮助
4.Docker学习之进阶使用
描述: 本章主要学习与记录了在进一步学习Docker容器中的一些基础名称解析与Docker与一些辅助软件配合使用来增加工作效率以及简化运维流程;
全栈工程师修炼指南
2022/09/28
1.6K0
4.Docker学习之进阶使用
推荐阅读
相关推荐
测试必会 | Docker 核心命令技能
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验