一、问题现象:容器启动失败,
msg="Handler for POST /v1.27/containers/create returned error: error creating overlay mount to /paasdata/docker/overlay2/97b4aa9aa223b788f577ea2ae05b9ea0604de5ec6cc4f582fad6b86adacd6454-init/merged: no space left on device"
进一步地,到容器所在的工作目录下去做mount操作,只要挂载点是docker工作目录的子目录,就会同样会报no space的错误。怀疑是环境的某类资源耗尽了
二、mount挂载点
linux上存在mnt命名空间,不通的每个进程都属于一个特定的mnt命令空间,可以通过ls -l /proc/$pid/ns 查看进程对应的命名空间,通过命令unshare --mount --propagation slave /bin/sh可以创建一个mnt命令空间。mount操作实际是对mnt命名空间的操作,进程的挂载点均是引用的这个mnt命名空间的挂载点,执行一次mount,对应mnt命名空间增加了一条mount信息,同一个mnt命名空间下的进程的mount挂载点也都会增加一条。
那对于不同mnt命名空间下的进程,他们的挂载事件是完全隔离的吗? 答案是否定的,他们可以通过共享组来将mount事件传播到其他的mnt的命名空间。可以通过cat /proc/$pid/mountinfo查看某个进程的挂载信息。也可以使用findmnt命令查看挂载点数结构。mountinfo信息的具体含义如下:
38 1 253:0 / / rw,relatime shared:1 - xfs /dev/mapper/ncl-root rw,seclabel,attr2,inode64,noquota
23 38 0:18 / /run rw,nosuid,nodev shared:23 - tmpfs tmpfs rw,seclabel,mode=75538
23表示本次mount产生的source mount id,38表示本次mount的dest mount id,即本次mount的父挂载点。第一个 “/” 表示本次挂载的挂载源是根文件系统,/run表示挂载点目录,后面是一些挂载属性,shared:23表示为shared共享组,组id为23(可能还会有master:id,它表示此mount源自于slave传播产生的挂载,如果没有的这列的话表示private挂载产生)第一个tmpfs表示tmpfs文件系统,第二个tmpfs表示tmpfs设备。
根据id(38)进行查找,发现第一条就是第二条的父挂载点,而这个dest mount在内核处理中,就会将其作为mnt_parent。
内核如何判断一条挂载的父挂载点? :在执行mount命令的进程mnt命名空间中的挂载点目录中,查找本次挂载的挂载点目录,如果该挂载点目录已经被挂载过,则设置本次挂载的父挂载点为上一次该挂载点目录的挂载点。如果本次挂载的挂载点在mnt命名空间中的挂载点目录中不存在,则查找本次挂载点目录的父目录,如果父目录在mnt命名空间中存在,则本身挂载的父挂载点就是该挂载点的父目录挂载是的挂载点
例如:
主机侧存在一条挂载点:
38 1 253:0 / / rw,relatime shared:1 - xfs /dev/mapper/ncl-root rw,seclabel,attr2,inode64,noquota
执行:mount -t tmpfs tmpfs /root/mount-test/run
51 38 0:39 / /root/mount-test/run rw,relatime shared:31 - tmpfs tmpfs rw,seclabel
1、在mnt命名空间中的挂载点目录中查找/root/mount-test/run,发现该目录没有被挂载过,继续第二步
2、继续查找父目录,即查找/root/mount-test,同样没有,执行第三步
3、继续查找/root,没有被挂载过,继续第四步
4、查找/, 发现有挂载点 “38 1 / /”
5、本次挂载点的父挂载点为38,所以本次挂载为 “51 38 / /root/mount-test/run”
三、mount共享组
在生成挂载点的时候,如果指定挂载属性为private/rprivate,则不属于任何共享组,如果设置为slave/rslave,则存在一个父组(自身为master)。如果设置为shared/rshared,则属于shared组。shared属性的挂载点,则会在不同的命名空间中相互传播mount事件,而slave属性的命名空间在产生mount事件时,只会将该mount事件传播给该挂载点的子组,不会传给父组,而private属性的挂载点,只会影响到自己的命名空间,不会传播给其他命名空间。
对于shared属性的mnt命名空间:
创建命名空间:
[root@host-10-89-230-30 data]# unshare --mount --propagation shared /bin/sh
sh-4.2# cd /data
sh-4.2# cat /proc/self/mountinfo |wc -l
35
sh-4.2# mount --bind /data/src-code /data/wxs
sh-4.2# cat /proc/self/mountinfo |wc -l
36
sh-4.2# cat /proc/self/mountinfo |grep wxs
173 170 252:16 /src-code /data/wxs rw,relatime shared:30 - xfs /dev/vdb rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
主机侧:
[root@host-10-89-230-30 ~]# cat /proc/self/mountinfo |wc -l
35
[root@host-10-89-230-30 ~]# cat /proc/self/mountinfo |wc -l
36
[root@host-10-89-230-30 ~]# cat /proc/self/mountinfo | grep wxs
210 49 252:16 /src-code /data/wxs rw,relatime shared:30 - xfs /dev/vdb rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
对于slave的mnt命令空间
[root@host-10-89-230-30 data]# unshare --mount --propagation slave /bin/sh
sh-4.2# mount --bind /data/src-code /data/wxs
sh-4.2# cat /proc/self/mountinfo |grep data
170 138 252:16 / /data rw,relatime master:30 - xfs /dev/vdb rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
173 170 252:16 /src-code /data/wxs rw,relatime master:30 - xfs /dev/vdb rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noqu
主机侧:(挂载事件没有传递到主机侧,即父组)
[root@host-10-89-230-30 ~]# cat /proc/self/mountinfo | grep data
49 94 252:16 / /data rw,relatime shared:30 - xfs /dev/vdb rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
[root@host-10-89-230-30 ~]#
从以上可知,新建命名空间中的master:30组是主机侧的shared:30的子组,在slave模式下,子组的挂载事件不会反向传播给父组。
在命名空间中确定组属:
[root@host-10-89-230-30 data]# mount --bind --make-slave /data/src-code /data/wxs
[root@host-10-89-230-30 data]# cat /proc/self/mountinfo |grep data
49 94 252:16 / /data rw,relatime shared:30 - xfs /dev/vdb rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
137 49 252:16 /src-code /data/wxs rw,relatime master:30 - xfs /dev/vdb rw,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota
流程如下:
1、查找该mnt命名空间,dest_dir挂载点目录是否有/data/wxs,没有找到,执行第二步
2、查找该mnt命名空间,dest_dir挂载点目录是否有/data/,找到了为/data的挂载点,挂载点的组属为shared:30
3、设置本次挂着的组属也为30,挂载方式指定为slave,所以最终组属为master:30,表示为组shared:30的slave子组。