理论上来讲,mount操作一定是发生在容器启动之后的(包括宿主机也如此);但是,docker只是在create好run的时候提供了挂载卷的方法,一旦容器被创建,我们将再没有机会给容器挂载新的卷了;如果非要这么做的话,只能销毁、重新创建容器,好生繁琐。
既然理论上可以在容器启动之后挂载新的卷,docker没有提供相应的API,那么又该如何做呢?
- 办法一: hack一下docker,提供这方面的功能; 缺点: 随着docker版本的升级,代码维护起来比较麻烦
- 办法二: 从系统层面来实现,参考: https://jpetazzo.github.io/2015/01/13/docker-mount-dynamic-volumes/
办法二还是比较科学的,这里测试了一下,确实好用,脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
#!/bin/sh set -e CONTAINER=$1 HOSTPATH=$2 CONTPATH=$3 REALPATH=$(readlink --canonicalize $HOSTPATH) FILESYS=$(df -P $REALPATH | tail -n 1 | awk '{print $6}') DEVICE=$(df -P $REALPATH | tail -n 1 | awk '{print $1}') while read DEV MOUNT JUNK do [ $DEV = $DEVICE ] && [ $MOUNT = $FILESYS ] && break done </proc/mounts [ $DEV = $DEVICE ] && [ $MOUNT = $FILESYS ] # Sanity check! while read A B C SUBROOT MOUNT JUNK do [ $MOUNT = $FILESYS ] && break done < /proc/self/mountinfo [ $MOUNT = $FILESYS ] # Moar sanity check! SUBPATH=$(echo $REALPATH | sed s,^$FILESYS,,) DEVDEC=$(printf "%d %d" $(stat --format "0x%t 0x%T" $DEV)) docker-enter $CONTAINER sh -c \ "[ -b $DEV ] || mknod --mode 0600 $DEV b $DEVDEC" docker-enter $CONTAINER sh -c "[ -d /tmpmnt ] || mkdir /tmpmnt" docker-enter $CONTAINER mount $DEV /tmpmnt docker-enter $CONTAINER sh -c "[ -d $CONTPATH ] || mkdir -p $CONTPATH" docker-enter $CONTAINER mount -o bind /tmpmnt/$SUBROOT/$SUBPATH $CONTPATH docker-enter $CONTAINER umount /tmpmnt docker-enter $CONTAINER rmdir /tmpmnt |
docker-enter 下载地址: https://github.com/jpetazzo/nsenter
注意:
- 这里用到了一个importenv的程序,可以参考容器环境变量来设置执行命令的环境变量,是个不错的办法,只是引入了一个其他的程序
- 这个要求容器中安装mount命令,该命令的依赖比较多,而且很少使用,所以,容器中一般都没有,需要手动安装,如果去掉那些依赖,单独安装一个mount命令会好一些
- 这个方法不适用于不基于块设备的文件系统,只有在
/proc/mounts
能正确得到块设备节点(上面谈到,并不总是能正确得到)的时候才能起作用。(比如: cephfs挂在的目录就不行)