LOADING

Follow me

浅谈 Docker容器运行时挂盘问题【zoues.com】
三月 30, 2017|DockerPaaS

浅谈 Docker容器运行时挂盘问题【zoues.com】

浅谈 Docker容器运行时挂盘问题【zoues.com】


在以往的虚拟机使用中,空间不够时,再挂载一块磁盘上去是很常见的需求处理方式,而在容器使用时,如果想要在其运行时挂载一块盘,却并非一件易事。


本文就将介绍下容器挂盘的相关知识,以及运行时挂盘的问题所在,并试着给出相应的解决方案。



容器磁盘的相关知识


Docker容器使用 volume,可以简单分为两种:


1.  使用宿主机本地目录


使用方式形如-v /host_absolute_path:/container_absolute_path


2.  使用 docker volume


使用方式形如-v volume_name:/container_absolute_path


浅谈 Docker容器运行时挂盘问题

本地卷 本地卷又可以进一步细分文件系统类型,如:


docker volume create –driver local –opt type=tmpfs –opt device=tmpfs –opt o=size=100m,uid=1000 –name foo

docker volume create –driver local –opt type=btrfs –opt device=/dev/sda2 –name foo


浅谈 Docker容器运行时挂盘问题

远程卷 支持远程卷的插件包括:convoy、flocker、glusterFs等等,这里不再详细展开。


本人一直从事网易云基础服务(蜂巢)相关项目的研发工作,在实际的项目中,远程卷管理实际是由上层编排工具 kubernetes来创建和管理的,Docker使用的是块设备已挂载的目录。


因此本文主要侧重于对第一种类型的介绍,即,如何在容器运行时挂载宿主机本地目录。



运行时挂载目录实现


1. 关键问题


浅谈 Docker容器运行时挂盘问题

块设备挂载问题 


块设备可以简单分为两类:容器启动前挂在宿主机上的块设备、启动后的挂载盘,前者在容器中是可见的,而后者因为容器的隔离性则不可见。因此,这里需要一些措施,将宿主机新增的块设备在容器中可见。


本文将利用宿主机和容器共享内核的特性,通过从宿主机传递块设备的主次设备号到容器中来打破这种隔离。


浅谈 Docker容器运行时挂盘问题

文件系统识别问题 


因为 Mount namespace的隔离,宿主机的目录对容器而言是没有实际意义的。这里搭配上面传入的块设备,通过挂载块设备、引入块设备根目录,使得传入的路径变得有意义。


浅谈 Docker容器运行时挂盘问题

容器权限控制问题

 

挂载路径需要 mount权限,容器默认是没有该权限的,当然,可以通过 –privileged、cap add等手段在启动时赋予权限,但是对运行时的容器无法新增(权限)。而且有些产品,如网易云基础服务(蜂巢),出于安全考虑,并没有开放太多权限,为了规避权限问题,这里采用 docker-enter在运行中的容器里执行命令。(https://github.com/jpetazzo/nsenter.git )


2. 实现演示


下面主要通过一些简单的脚本命令,从原理出发,显示实现运行时挂载新增盘的路径(以下操作基于docker 1.12.0)


一些准备工作:在宿主机上挂一块新盘到 /root/new-disk,新盘在容器中不可见。


接下来,我们要实现挂载宿主机 /root/new-disk/container1目录到容器 test的 /data目录,以下是操作过程:


①  宿主机获取必要信息


为了在容器中挂载,需要从宿主机获取必要信息,这里给出本人测试的一些参考结果:DEV: /dev/vdf1; DEVDEC: 254 81; SUBROOT: ; SUBPATH: /root/new-disk/container1。下面是需要在宿主机上运行的命令:

FILESYS=$(df -P /root/new-disk/container1 | tail -n 1 | awk ‘{print $1}’)


while read DEV MOUNT JUNK; do

        if [ “$DEV”x == “$FILESYS”x ]; then

                break

        fi

done < /proc/mounts


while read A B C SUBROOT MOUNT JUNK; 

do

        if [ “$MOUNT”x == “$FILESYS”x ]; then

                break

        fi

done < /proc/self/mountinfo


SUBPATH=$(echo /root/new-disk/container1 | sed s,^$FILESYS,,) 

DEVDEC=$(printf “%d %d” $(stat –format “0x%t 0x%T” $DEV)) # 块设备主次设备号


②  在容器中挂载该盘及其目录


在容器中运行以下命令,就可以在 test容器 /data目录下,看到宿主机 /root/new-disk/container1目录下的内容。


docker-enter test sh -c “mknod –mode 0600 $DEV b $DEVDEC” # 用主次设备号新建块设备

docker-enter test mkdir /tmpmnt 

docker-enter test mount $DEV /tmpmnt 

docker-enter test mkdir -p /data 

docker-enter test mount -o bind /tmpmnt/$SUBROOT/$SUBPATH /data # 用相对块设备根目录的路径来挂载宿主机路径

docker-enter test unmount /tmpmnt 

docker-enter test rmdir /tmpmnt


注:本文的写作对以下链接中的文章亦有参考 https://jpetazzo.github.io/2015/01/13/docker-mount-dynamic-volumes/


END



精彩文章回顾

点击图片轻松阅读

浅谈 Docker容器运行时挂盘问题

Docker 容器的显示问题及修复

浅谈 Docker容器运行时挂盘问题

Docker容器的自动化监控实现

no comments
Share

发表评论