Docker存储 我们可以将数据保存在容器中,但是这样存在一些缺点:当容器停止运行的时候,我们无法使用数据,并且容器被删除时,数据没有被保存下来。数据保存在容器中的可写层中,我们无法轻松的将数据移动到其它地方。 针对上述的缺点,有些数据,例如数据库文件,我们不应该将其保存在镜像或者容器的可写层中。Docker提供三种不同的方式将数据从Docker主机挂载到容器中,分别为卷(volumes),绑定挂载(bindmounts),临时文件系统(tmpfs)。很多时候,volumes总是正确的选择。volumes,卷存储在Docker管理的主机文件系统的某个目录(varlibdockervolumes)里bindmounts,绑定挂载,可以将主机的文件或目录挂载到容器中tmpfs,仅存储在主机内存中,而不会写入主机文件系统 无论使用上述的哪一种方式,数据在容器内看上去都是一样的。它被认为是容器文件系统的目录或文件。卷列表 对于三种不同的存储数据的方式来说,卷是唯一完全由Docker管理的。它更容易备份或迁移,并且我们可以使用DockerCLI命令来管理卷。 列出本地可用的卷列表:〔rootVM017centos〕dockervolumelsDRIVERVOLUMENAMElocal0e15a7c0f491bbf500f419ec2637be6a298922cd9d9831b3875363a7f34971cblocal3fdec394f801640e1a39240be7bd627eb92a6af259844bbe8f5c0ba2a5baf9e5创建卷〔rootVM017centos〕dockervolumecreate3a513b26b0bf00087149095c6dbbc6101a5f70efdc15d2430d8e62f4e92715f9 这种由系统随机生成名称的卷称为匿名卷,匿名卷名称不具备可读性,使用起来不太方便,所以创建卷时一般会指定其name。例如我们创建一个名为volume1的卷。〔rootVM017centos〕dockervolumecreatevolume1volume1〔rootVM017centos〕dockervolumelsDRIVERVOLUMENAMElocal0e15a7c0f491bbf500f419ec2637be6a298922cd9d9831b3875363a7f34971cblocal3a513b26b0bf00087149095c6dbbc6101a5f70efdc15d2430d8e62f4e92715f9localvolume1用卷启动一个容器 创建好卷之后,我们可以用卷来启动一个容器,这里首先需要学习dockercontainerrun命令的两个参数:v或volume由三个冒号(:)分隔的字段组成,〔HOSTDIR:〕CONTAINERDIR〔:OPTIONS〕。HOSTDIR代表主机上的目录或数据卷的名字。省略该部分时,会自动创建一个匿名卷。如果是指定主机上的目录,需要使用绝对路径。CONTAINERDIR代表将要挂载到容器中的路径OPTIONS代表配置,例如设置为只读(ro),或者仅能被该容器使用(Z),或者可以被多个容器共享(z)。多个配置项由逗号分隔。例如,我们使用vvolume1:volume1:ro,z。代表的是意思是将卷volume1挂载到容器中的volume1目录。ro,z代表该卷被设置为只读(ro),并且可以被多个容器同时使用(z)mount由多个键值对组成,键值对之间由逗号分隔。例如:typevolume,sourcevolume1,destinationvolume1,rotrue。type指定类型,可以指定为bind,volume,tmpfs。source当类型为volume时,指定卷名称,省略该字段会新建一个卷。当类型为bind时,指定路径。可以使用缩写src。destination挂载到容器中的路径。可以使用缩写dst或target。readonly读写配置项,true或false。可以使用缩写ro。 对于前面创建的卷volume1,可使用如下命令来在容器中使用:〔rootVM017centos〕dockercontainerrunitnamehellodocker3vvolume1:volume1rmubuntubashUnabletofindimageubuntu:latestlocallylatest:Pullingfromlibraryubuntu423ae2b273f4:Pullcompletede83a2304fa1:Pullcompletef9a83bce3af0:Pullcompleteb6b53be908de:PullcompleteDigest:sha256:04d48df82c938587820d7b6006f5071dbbffceb7ca01d2814f81857c631d44dfStatus:Downloadednewerimageforubuntu:latestroota23cea8fe875: 使用mount的命令如下:〔rootVM017centos〕dockerrunitnamehellodocker4mounttypevolume,srcvolume1,targetvolume1rmubuntubash 可以看出mount的可读性更好。所以推荐大家使用mount 上述操作,我们运行了两个容器,并分别挂载了一个卷。对于这两个容器来说,由于挂载的是同一个卷,所以它们将共享该数据卷。多个容器共享数据卷时,需要注意并发读写问题。可以分别连接到两个容器中,操作数据来验证数据是同步的。bindmounts 绑定挂载(bindmounts)通过将主机上的目录挂载到容器中,使得容器可以操作和修改主机上的文件。 例如,我们将homehellodocker目录挂载到容器中的homehellodocker目录下,使用的命令如下:〔rootVM017centoshellodocker〕dockerrunitvhomehellodocker:homehellodockernamehellodocker4rmubuntubashroot9d89e44a06a8:Croot9d89e44a06a8:lsbinbootdevetchomeliblib64mediamntoptprocrootrunsbinsrvsystmpusrvarroot9d89e44a06a8:cdhomeroot9d89e44a06a8:homelshellodockerroot9d89e44a06a8:homecdhellodockerroot9d89e44a06a8:homehellodockerlstest1test2root9d89e44a06a8:homehellodocker 而如果使用mount,相应的语句如下:〔rootVM017centoshellodocker〕dockerrunitmounttypebind,srchomehellodocker,targethomehellodockernamehellodocker5rmubuntubash 如果挂载时指定的容器目录已存在,则该目录将被覆盖(还存在只是被隐藏了,因为其位于更下层)。并且如果主机上的目录不存在,会自动创建该目录。 上述两个操作针对的是目录,而对于挂载文件来说,可能会出现一些特殊情况,涉及到绑定挂载和使用卷的区别。下面我们重现这一操作: 首先在当前目录,即homehellodocker目录下,创建一个test。txt文件。并向其中写入文本内容test1:echotest1test。txt 接着创建一个容器hellodocker6,将test。txt文件挂载到容器中的test。txt路径,并查看容器中test。txt文件的内容:〔rootVM017centoshellodocker〕dockerrunitvhomehellodockertest。txt:test。txtnamehellodocker6ubuntubinbashroot99d55b8d4d8a:cattest。txttest1 这时新打开一个终端,通过echo命令向homehellodockertest。txt文件追加内容test2,并在容器中查看test。txt文件的内容:echotest2test。txtroot99d55b8d4d8a:cattest。txttest1test2 这时无论是在容器中还是主机上都能查看到该文件的最新内容。接下来在主机上查看test。txt的inode号,并使用vim编辑该文件,添加test3,并查看该文件的内容:〔rootVM017centoshellodocker〕lsitest。txt527823test。txt〔rootVM017centoshellodocker〕vimtest。txt〔rootVM017centoshellodocker〕lsitest。txt527050test。txt 在主机上使用vim编辑后,通过vim做出的修改并不能在容器中查看到root68c277025b02:cattest。txttest1test2 这是因为vim编辑文件的时候,会将文件内容暂存到一个临时文件中,退出保存后会删除原来的文件,并将临时文件重命名为原文件。但是我们标识文件是通过inode,因此Docker绑定的依然是旧的主机文件,所以容器中看到的依然是旧的内容。 对于数据卷来说,由docker完全管理,而绑定挂载需要我们自己去维护。我们需要自己手动去处理这些问题,这些问题并不仅仅是上面演示的这些,还有用户权限,SELINUX等。使用tmpfs挂载数据 tmpfs只存储在主机的内存中。当容器停止时,相应的数据就会被移除。dockerrunitmounttypetmpfs,targettestnamehellodocker7rmubuntubash