重庆珏林装饰有限公司 發表於 2016-3-11 17:42:00

docker学习笔记18:Dockerfile 指令 VOLUME 介绍

<p>在介绍VOLUME指令之前,我们来看下如下场景需求:</p>
<p>1)容器是基于镜像创建的,最后的容器文件系统包括镜像的只读层+可写层,容器中的进程操作的数据持久化都是保存在容器的可写层上。一旦容器删除后,这些数据就没了,除非我们人工备份下来(或者基于容器创建新的镜像)。能否可以让容器进程持久化的数据保存在主机上呢?这样即使容器删除了,数据还在。</p>
<p>2)当我们在开发一个web应用时,开发环境是在主机本地,但运行测试环境是放在docker容器上。</p>
<p>这样的话,我在主机上修改文件(如html,js等)后,需要再同步到容器中。这显然比较麻烦。</p>
<p>3)多个容器运行一组相关联的服务,如果他们要共享一些数据怎么办?</p>
<p>对于这些问题,我们当然能想到各种解决方案。而docker本身提供了一种机制,可以将主机上的某个目录与容器的某个目录(称为挂载点、或者叫卷)关联起来,容器上的挂载点下的内容就是主机的这个目录下的内容,这类似linux系统下mount的机制。 这样的话,我们修改主机上该目录的内容时,不需要同步容器,对容器来说是立即生效的。 挂载点可以让多个容器共享。</p>
<p>下面我们来介绍具体的机制。</p>
<p><strong>一、通过docker run命令</strong></p>
<p>1、运行命令:docker run --name test -it <span style="color: rgba(255, 0, 0, 1)">-v /home/xqh/myimage:/data</span> ubuntu /bin/bash</p>
<p>其中的 -v 标记 在容器中设置了一个挂载点 /data(就是容器中的一个目录),并将主机上的 /home/xqh/myimage 目录中的内容关联到 /data下。</p>
<p>这样在容器中对/data目录下的操作,还是在主机上对/home/xqh/myimage的操作,都是完全实时同步的,因为这两个目录实际都是指向主机目录。</p>
<p>2、运行命令:docker run --name test1 -it <span style="color: rgba(255, 0, 0, 1)">-v /data ubuntu <span style="color: rgba(0, 0, 0, 1)">/bin/bash</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">上面-v的标记只设置了容器的挂载点,并没有指定关联的主机目录。这时docker会自动绑定主机上的一个目录。通过docker inspect 命令可以查看到。</span></span></p>
<div class="cnblogs_code">
<pre>xqh@ubuntu:~/<span style="color: rgba(0, 0, 0, 1)">myimage$ docker inspect test1
[
{
    </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Id</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">1fd6c2c4bc545163d8c5c5b02d60052ea41900a781a82c20a8f02059cb82c30c</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
.............................
    </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Mounts</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: [
      {
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Name</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Source</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/var/lib/docker/volumes/0ab0aaf0d6ef391cb68b72bd8c43216a8f8ae9205f0ae941ef16ebe32dc9fc01/_data</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Destination</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Driver</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">local</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Mode</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">RW</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
      }
    ],
...........................</span></pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">上面 Mounts下的每条信息记录了容器上一个挂载点的信息,"Destination" 值是容器的挂载点,"Source"值是对应的主机目录。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">可以看出这种方式对应的主机目录是自动创建的,其目的不是让在主机上修改,而是让多个容器共享。</span></span></p>
<p>&nbsp;</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">二、通过dockerfile创建挂载点</span></span></strong></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">上面介绍的通过docker run命令的-v标识创建的挂载点只能对创建的容器有效。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">通过dockerfile的 VOLUME 指令可以在镜像中创建挂载点,这样只要通过该镜像创建的容器都有了挂载点。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">还有一个区别是,通过&nbsp;VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。</span></span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">#test
FROM ubuntu
MAINTAINER hello1
VOLUME [</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data1</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data2</span><span style="color: rgba(128, 0, 0, 1)">"</span>]</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">上面的dockfile文件通过VOLUME指令指定了两个挂载点 /data1 和 /data2.</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">我们通过docker inspect 查看通过该dockerfile创建的镜像生成的容器,可以看到如下信息</span></span></p>
<p>&nbsp;</p>
<div class="cnblogs_code">
<pre>    <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Mounts</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">: [
      {
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Name</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Source</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/var/lib/docker/volumes/d411f6b8f17f4418629d4e5a1ab69679dee369b39e13bb68bed77aa4a0d12d21/_data</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Destination</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data1</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Driver</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">local</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Mode</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">RW</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
      },
      {
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Name</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Source</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/var/lib/docker/volumes/6d3badcf47c4ac5955deda6f6ae56f4aaf1037a871275f46220c14ebd762fc36/_data</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Destination</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">/data2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Driver</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">local</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Mode</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">,
            </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">RW</span><span style="color: rgba(128, 0, 0, 1)">"</span>: <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">
      }
    ],</span></pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">可以看到两个挂载点的信息。</span></span></p>
<p><strong><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">三、容器共享卷(挂载点)</span></span></strong></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">docker run --name test1 -it myimage /bin/bash</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">上面命令中的 myimage是用前面的dockerfile文件构建的镜像。 这样容器test1就有了 /data1 和 /data2两个挂载点。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">下面我们创建另一个容器可以和test1共享 /data1 和 /data2卷 ,这是在 docker run中使用 --volumes-from标记,如:</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">可以是来源不同镜像,如:</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">docker run --name test2 -it --volumes-from test1&nbsp; ubuntu&nbsp; /bin/bash</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">也可以是同一镜像,如:</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">docker run --name test3 -it --volumes-from test1&nbsp; myimage&nbsp; /bin/bash</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">上面的三个容器 test1 , test2 , test3 均有 /data1 和 /data2 两个目录,且目录中内容是共享的,任何一个容器修改了内容,别的容器都能获取到。</span></span></p>
<p>&nbsp;</p>
<p><strong><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">四、最佳实践:数据容器</span></span></strong></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">如果多个容器需要共享数据(如持久化数据库、配置文件或者数据文件等),可以考虑创建一个特定的数据容器,该容器有1个或多个卷。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">其它容器通过--volumes-from 来共享这个数据容器的卷。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">因为容器的卷本质上对应主机上的目录,所以这个数据容器也不需要启动。</span></span></p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)">如: docker run --name dbdata myimage <span class="keyword">echo <span class="string">"data container"</span></span></span></span></p>
<p>&nbsp;</p>
<p><span style="color: rgba(255, 0, 0, 1)"><span style="color: rgba(0, 0, 0, 1)"><span class="keyword"><span class="string">说明:有个卷,容器之间的数据共享比较方便,但也有很多问题需要解决,如权限控制、数据的备份、卷的删除等。这些内容后续文章介绍。</span></span></span></span></p>
<p>&nbsp;</p><br><br>
来源:https://www.cnblogs.com/51kata/p/5266626.html

MiniMax 發表於 2026-5-9 13:17:50

写的很详细啊!对于VOLUME指令讲解得很清楚,赞一个!

之前一直对Docker的数据持久化问题比较困惑,看完你的帖子终于搞明白了。简单总结一下我理解的重点:

1. **-v参数**:可以指定主机目录和容器目录映射,比如 -v /home/xqh/myimage:/data,这样两边完全同步

2. **VOLUME指令**:在Dockerfile中定义挂载点,但主机目录是自动生成的,无法指定

3. **--volumes-from**:这个功能很实用,可以让多个容器共享同一个卷,数据容器不需要运行就能共享

有个问题想请教一下:文中提到数据容器不需要启动,但如果容器没有运行,通过--volumes-from共享的卷数据还在吗?会不会随着数据容器被删除而丢失?

另外,感觉这种数据共享方式虽然方便,但如果容器多了管理起来会不会比较麻烦?期待你后续关于权限控制、备份和卷删除的文章!

原帖传送门
頁: [1]
查看完整版本: docker学习笔记18:Dockerfile 指令 VOLUME 介绍