详解docker中容器devicemapper设备的挂载流程

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 详解docker中容器devicemapper设备的挂载流程事故起因版本说明:本文中docker版本主要基于1.10版本,操作系统为centos7。devicemapper在文中缩写为dm。某个用户的容器启动不起来,启动时候一直报错。

详解docker中容器devicemapper设备的挂载流程
事故起因
版本说明:本文中docker版本主要基于1.10版本,操作系统为centos7。devicemapper在文中缩写为dm。

某个用户的容器启动不起来,启动时候一直报错。通过docker log查看日志,可以看到报错信息如下

Timestamp: 2019-04-01 16:19:26.33690413 +0800 CST
Code: System error

Message: can't create pivot_root dir , error mkdir /export/docker/devicemapper/mnt/7a35b08cc8815ef439dfcc74fd375e2fbb618208674d6eff1ea5d0b61cc7ef1c/rootfs/.pivot_root492082001: no space left on device
对照docker源码,可以看到报错位置,就是在容器启动时候,docker会在容器中创建一个临时文件夹。而由于空间不足,因此导致报错,容器无法启动。

pivotDir, err := ioutil.TempDir(tmpDir, ".pivot_root")
if err != nil {

return fmt.Errorf("can't create pivot_root dir %s, error %v", pivotDir, err)
AI 代码解读

}
初步可以判断是由于用户将dm的根目录磁盘写满了导致。那么要解决这个问题,其实思路也就很简单,就是将容器的dm设备手动挂载起来,然后清理冗余文件后,再恢复。那么在docker中,是如何将容器的dm盘进行创建挂载的,笔者对此进行了一下梳理。

docker中容器的dm盘挂载原理
获取dm设备信息
这里我们假设要模拟的是f34cee76e36a容器的挂载。
首先进入到docker的存储目录,可以从image的层文件夹中根据容器的id,获取mount-id。
而后从devicemapper/metadata/文件夹中,根据mount-id,获取device_id。这里,该容器的device_id为34709。

[root@localhost docker]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f34cee76e36a xuxinkun/kubesql "kubesql-server" 3 weeks ago Exited (137) 3 hours ago kubesql-server
[root@localhost docker]# cat image/devicemapper/layerdb/mounts/f34cee76e36af13dbda34f78406ebe1c9a426d16e4eaae02055ace6b557b7539/mount-id
dad0ce9e1adcfe76df319443f429698eafa52dd6c6cb4fb8192f0846656f8824
[root@localhost docker]# cat devicemapper/metadata/dad0ce9e1adcfe76df319443f429698eafa52dd6c6cb4fb8192f0846656f8824
{"device_id":34709,"size":10737418240,"transaction_id":844170,"initialized":false,"deleted":false}
先看一下已经创建的dm设备列表和table。

[root@localhost docker]# dmsetup ls
cl-swap (253:1)
cl-root (253:0)
docker-253:2-3693860-e85dd79353abe6967cbc4f968934ae078d4d9da02010033b73a3df9659e4d547 (253:4)
cl-home (253:2)
docker-253:2-3693860-pool (253:3)
[root@localhost docker]# dmsetup table
cl-swap: 0 32899072 linear 8:2 2048
cl-root: 0 104857600 linear 8:2 1647560704
docker-253:2-3693860-e85dd79353abe6967cbc4f968934ae078d4d9da02010033b73a3df9659e4d547: 0 20971520 thin 253:3 34719
cl-home: 0 1614659584 linear 8:2 32901120
docker-253:2-3693860-pool: 0 167772160 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing
这其中主要要关注的是docker-253:2-3693860-pool,也就是253:3这个设备。后面的所有的docker容器的dm设备都是从这个pool中分出去的。
从table中可以看到一个已经创建好的,它的table是0 20971520 thin 253:3 34719。table的格式如下

logical_start_sector num_sectors target_type target_args
开始扇区 扇区数 设备类型 设备参数
20971520的扇区数应与docker启动时为容器分配的容量相关。

其中,设备参数的34719即为容器对应的device_id。

创建dm设备
那么现在模拟容器挂载,首先创建一个dm设备。

[root@localhost docker]# dmsetup create docker-253:2-3693860-dad0ce9e1adcfe76df319443f429698eafa52dd6c6cb4fb8192f0846656f8824 --table "0 20971520 thin 253:3 34709"
然后可以查看下dm设备。

[root@localhost docker]# dmsetup ls
cl-swap (253:1)
cl-root (253:0)
docker-253:2-3693860-dad0ce9e1adcfe76df319443f429698eafa52dd6c6cb4fb8192f0846656f8824 (253:5)
docker-253:2-3693860-e85dd79353abe6967cbc4f968934ae078d4d9da02010033b73a3df9659e4d547 (253:4)
cl-home (253:2)

[root@localhost tmp]# ls /dev/dm-*
/dev/dm-0 /dev/dm-1 /dev/dm-2 /dev/dm-3 /dev/dm-4 /dev/dm-5
可以看到,新增了一个dm-5的设备。

当然,也可以在/dev/mapper下查看

挂载dm设备
现在将/dev/dm-5设备挂载到自己创建了/tmp/test目录下。

[root@localhost docker]# mount /dev/dm-5 /tmp/test
[root@localhost docker]# ll /tmp/test/
total 4
-rw------- 1 root root 64 Mar 11 15:40 id
drwxr-xr-x 16 root root 274 Apr 2 09:54 rootfs
[root@localhost docker]# ll /tmp/test/rootfs/
total 16
-rw-r--r-- 1 root root 12076 Dec 5 09:37 anaconda-post.log
lrwxrwxrwx 1 root root 7 Dec 5 09:36 bin -> usr/bin
drwxr-xr-x 4 root root 43 Mar 11 17:50 dev
drwxr-xr-x 48 root root 4096 Mar 11 17:50 etc
drwxr-xr-x 3 root root 21 Mar 11 17:38 home
lrwxrwxrwx 1 root root 7 Dec 5 09:36 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Dec 5 09:36 lib64 -> usr/lib64
drwxr-xr-x 2 root root 6 Apr 11 2018 media
drwxr-xr-x 2 root root 6 Apr 11 2018 mnt
drwxr-xr-x 2 root root 6 Apr 11 2018 opt
drwxr-xr-x 2 root root 6 Dec 5 09:36 proc
dr-xr-x--- 4 root root 140 Mar 11 17:37 root
drwxr-xr-x 12 root root 163 Mar 11 17:50 run
lrwxrwxrwx 1 root root 8 Dec 5 09:36 sbin -> usr/sbin
drwxr-xr-x 2 root root 6 Apr 11 2018 srv
drwxr-xr-x 2 root root 6 Dec 5 09:36 sys
drwxrwxrwt 7 root root 132 Mar 11 17:38 tmp
drwxr-xr-x 13 root root 155 Dec 5 09:36 usr
drwxr-xr-x 18 root root 238 Dec 5 09:36 var
可以在目录下看到rootfs文件夹,该文件夹下即为容器的所有文件。而后找出冗余文件删除即可。

卸载移除设备
最后清理恢复,卸载目录,移除dm设备。

[root@localhost docker]# umount /tmp/test
[root@localhost docker]# dmsetup remove docker-253:2-3693860-e85dd79353abe6967cbc4f968934ae078d4d9da02010033b73a3df9659e4d547
重启容器后,恢复正常。至此,该问题得以修复。

以上是手动进行容器dm设备的创建挂载流程。其实在docker中,也基本上是这样来进行操作的。具体代码可以参考graphdriver下的devmapper中的相关流程。代码这里就不再一一走读了。

docker中mnt挂载点不可见的问题
在这里顺带还解释下docker挂载的一个疑惑,就是docker中dm设备最终都会mount到devicemapper/mnt/{mount-id}/目录下。

但是在/proc/mounts下并不可见。这是因为docker daemon单独创建了一个mount的namespace。

[root@localhost tmp]# ll /proc/1/ns/mnt
lrwxrwxrwx 1 root root 0 Mar 19 19:03 /proc/1/ns/mnt -> mnt:[4026531840]
[root@localhost tmp]# ps -fe|grep docker
root 845 23449 0 17:04 pts/1 00:00:00 grep --color=auto docker
root 23121 1 0 09:09 ? 00:00:38 /usr/bin/docker-current daemon --selinux-enabled --log-driver=journald -H tcp://127.0.0.1:5050 -H unix:///var/run/docker.sock -g /home/docker --storage-opt dm.blkdiscard=false --storage-opt dm.mountopt=nodiscard --storage-opt dm.loopdatasize=80G --storage-opt dm.loopmetadatasize=4G
[root@localhost tmp]# ll /proc/23121/ns/mnt
lrwxrwxrwx 1 root root 0 Apr 2 10:25 /proc/23121/ns/mnt -> mnt:[4026532450]
23121为docker daemon的进程id。可以通过查看该进程的mounts即可看到相应的挂载信息。

[root@localhost tmp]# cat /proc/23121/mounts|grep mnt
/dev/mapper/docker-253:2-3693860-e85dd79353abe6967cbc4f968934ae078d4d9da02010033b73a3df9659e4d547 /home/docker/devicemapper/mnt/e85dd79353abe6967cbc4f968934ae078d4d9da02010033b73a3df9659e4d547 xfs rw,relatime,nouuid,attr2,inode64,logbsize=64k,sunit=128,swidth=128,noquota 0 0
当然,也可以通过nsenter切入到docker daemon进程的mount ns下进行查看。

[root@localhost tmp]# nsenter -t 23121 -m mount -l|grep mnt
/dev/mapper/docker-253:2-3693860-e85dd79353abe6967cbc4f968934ae078d4d9da02010033b73a3df9659e4d547 on /home/docker/devicemapper/mnt/e85dd79353abe6967cbc4f968934ae078d4d9da02010033b73a3df9659e4d547 type xfs (rw,relatime,nouuid,attr2,inode64,logbsize=64k,sunit=128,swidth=128,noquota)
作者:xuxinkun
出处:xinkun的博客
链接:https://www.cnblogs.com/xuxinkun/

目录
打赏
0
0
0
0
58
分享
相关文章
zabbix7.0.9安装-以宝塔安装形式-非docker容器安装方法-系统采用AlmaLinux9系统-最佳匹配操作系统提供稳定运行环境-安装教程完整版本-优雅草卓伊凡
zabbix7.0.9安装-以宝塔安装形式-非docker容器安装方法-系统采用AlmaLinux9系统-最佳匹配操作系统提供稳定运行环境-安装教程完整版本-优雅草卓伊凡
92 30
揭秘 Microsoft.Docker.SDK:让容器开发更轻松的强大工具揭秘
随着云计算和容器技术的快速发展,`Docker` 已经成为容器化技术的事实标准。`Microsoft` 作为 `Docker` 的主要支持者和参与者,推出了 `Microsoft.Docker.SDK`,旨在帮助开发者更轻松地进行容器开发。本文将深入揭秘 Microsoft.Docker.SDK 的功能、使用方法以及它在容器开发中的应用。
42 12
docker容器为啥会开机自启动
通过配置适当的重启策略,Docker容器可以在主机系统重启后自动启动。这对于保持关键服务的高可用性和自动恢复能力非常有用。选择适合的重启策略(如 `always`或 `unless-stopped`),可以确保应用程序在各种情况下保持运行。理解并配置这些策略是确保Docker容器化应用可靠性的关键。
330 93
自学软硬件第755 docker容器虚拟化技术youtube视频下载工具
docker容器虚拟化技术有什么用?怎么使用?TubeTube 项目使用youtube视频下载工具
Docker Desktop 4.38 安装与配置全流程指南(Windows平台)
Docker Desktop 是容器化应用开发与部署的一体化工具,支持本地创建、管理和运行 Docker 容器。4.38 版本新增 GPU 加速、WSL 2 性能优化和 Kubernetes 1.28 集群管理功能,适用于微服务开发和 CI/CD 流水线搭建。安装要求为 Windows 10 2004 及以上(64 位),需启用 Hyper-V 或 WSL 2。硬件最低配置为 4GB 内存、20GB 存储和虚拟化技术支持的 CPU。安装步骤包括启用系统功能、下载并运行安装程序,完成后配置镜像加速并验证功能。常见问题涵盖 WSL 2 安装不完整、磁盘空间清理及容器外网访问等。
1183 13
Docker+consul容器服务的更新与发现
通过本文的介绍,我们详细探讨了如何结合Docker和Consul来实现容器服务的更新与发现。通过Consul的服务注册和发现功能,可以高效地管理和监控容器化服务,确保系统的高可用性和可扩展性。希望本文能帮助您在实际项目中更好地应用Docker和Consul,提高系统的可靠性和管理效率。
75 23
ubuntu22 编译安装docker,和docker容器方式安装 deepseek
本脚本适用于Ubuntu 22.04,主要功能包括编译安装Docker和安装DeepSeek模型。首先通过Apt源配置安装Docker,确保网络稳定(建议使用VPN)。接着下载并配置Docker二进制文件,创建Docker用户组并设置守护进程。随后拉取Debian 12镜像,安装系统必备工具,配置Ollama模型管理器,并最终部署和运行DeepSeek模型,提供API接口进行交互测试。
412 15
容器技术实践:在Ubuntu上使用Docker安装MySQL的步骤。
通过以上的操作,你已经步入了Docker和MySQL的世界,享受了容器技术给你带来的便利。这个旅程中你可能会遇到各种挑战,但是只要你沿着我们划定的路线行进,你就一定可以达到目的地。这就是Ubuntu、Docker和MySQL的灵魂所在,它们为你开辟了一条通往新探索的道路,带你亲身感受到了技术的力量。欢迎在Ubuntu的广阔大海中探索,用Docker技术引领你的航行,随时准备感受新技术带来的震撼和乐趣。
27 16
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
371 78
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等