给一个正在运行的Docker容器动态添加Volume |
您所在的位置:网站首页 › docker容器文件挂载 › 给一个正在运行的Docker容器动态添加Volume |
给一个正在运行的Docker容器动态添加Volume 本文转自:http://dockone.io/article/149 【编者的话】之前有人问我Docker容器启动之后还能否再挂载卷,考虑到mnt命名空间的工作原理,我一开始认为这很难实现。不过现在Petazzoni通过使用nsenter和绑定挂载实现了这个需求,你可以在你的环境中测试下。 之前有人问我Docker容器启动之后还能否再挂载卷,考虑mnt命名空间的工作原理,我一开始认为这很难实现。不过现在我认为是它实现的。 简单来说,要想将磁盘卷挂载到正在运行的容器上,我们需要: 使用nsenter将包含这个磁盘卷的整个文件系统mount到临时挂载点上; 从我们想当作磁盘卷使用的特定文件夹中创建绑定挂载(bind mount)到这个磁盘卷的位置; umount第一步创建的临时挂载点。 注意事项在下面的示例中,我故意包含了$符号来表示这是Shell命令行提示符,以帮助大家区分哪些是你需要输入的,哪些是机器回复的。有一些多行命令,我也继续用>。我知道这样使得例子里的命令无法轻易得被拷贝粘贴。如果你想要拷贝粘贴代码,请查看文章最后的示例脚本。 详细步骤下面示例的前提是你已经使用如下命令启动了一个简单的名为charlie的容器: $ docker run --name charlie -ti ubuntu bash我们需要做的是将宿主文件夹/home/jpetazzo/Work/DOCKER/docker挂载到容器里的/src目录。好了,让我们开始吧。 nsenter 首先,我们需要nsenter以及docker-enter帮助脚本。为什么?因为我们要从容器中mount文件系统。由于安全性的考虑,容器不允许我们这么做。使用nsenter,我们可以突破上述安全限制,在容器的上下文(严格地说,是命名空间)中运行任意命令。当然,这必须要求拥有Docker宿主机的root权限。nsenter最简单的安装方式是和docker-enter脚本关联执行: $ docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter更多细节,请查看nsenter项目主页。 找到文件系统 我们想要在容器里挂载包含宿主文件夹(/home/jpetazzo/Work/DOCKER/docker)的文件系统。那我们就需要找出哪个文件系统包含这个目录。 首先,我们需要canonicalize(或者解除引用)文件,以防这是一个符号链接,或者它的路径包含符号链接: $ readlink --canonicalize /home/jpetazzo/Work/DOCKER/docker /home/jpetazzo/go/src/github.com/docker/docker哈,这的确是一个符号链接!让我们将其放入一个环境变量中: $ HOSTPATH=/home/jpetazzo/Work/DOCKER/docker $ REALPATH=$(readlink --canonicalize $HOSTPATH)接下来,我们需要找出哪个文件系统包含这个路径。我们使用一个有点让人意想不到的工具来做,它就是df: $ df $REALPATH Filesystem 1K-blocks Used Available Use% Mounted on /sda2 245115308 156692700 86157700 65% /home/jpetazzo使用-P参数(强制使用POSIX格式,以防是exotic df,或者是其他人在Solaris或者BSD系统上装Docker时运行的df),将结果也放到一个变量里: $ FILESYS=$(df -P $REALPATH | tail -n 1 | awk '{print $6}')找到文件系统的设备(和sub-root) 现在,系统里已经没有绑定挂载(bind mounts)和BTRFS子卷了,我们仅仅需要查看/proc/mounts,找到对应于/home/jpetazzo文件系统的设备就可以了。但是在我的系统里,/home/jpetazzo是BTRFS池的子卷,要想得到子卷的信息(或者bind mount信息),需要查看/proc/self/moutinfo。 如果你从来没有听说过mountinfo,可以查看内核文档的proc.txt。 首先,得到文件系统设备信息: $ while read DEV MOUNT JUNK > do [ $MOUNT = $FILESYS ] && break > done do [ $MOUNT = $FILESYS ] && break > done "[ -b $DEV ] || mknod --mode 0600 $DEV b $DEVDEC"创建临时挂载点挂载文件系统: $ docker-enter charlie -- mkdir /tmpmnt $ docker-enter charlie -- mount $DEV /tmpmnt确保卷挂载点存在,bind mount卷: $ docker-enter charlie -- mkdir -p /src $ docker-enter charlie -- mount -o bind /tmpmnt/$SUBROOT/$SUBPATH /src删除临时挂载点: $ docker-enter charlie -- umount /tmpmnt $ docker-enter charlie -- rmdir /tmpmnt(我们并不清除设备节点。一开始就检查设备是否存在可能有点多余,但是现在再检查就已经很复杂了。) 大功告成! 让一切自动化下面这段可以直接拷贝粘贴了。 #!/bin/sh set -e CONTAINER=charlie HOSTPATH=/home/jpetazzo/Work/DOCKER/docker CONTPATH=/src REALPATH=$(readlink --canonicalize $HOSTPATH) FILESYS=$(df -P $REALPATH | tail -n 1 | awk '{print $6}') while read DEV MOUNT JUNK do [ $MOUNT = $FILESYS ] && break done |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |