Docker数据储存

docker ginotang 1116℃ 0评论

管理Docker中的数据

在容器中创建以及修改的文件默认都被保存在容器的可写层,这意味着:

  • 当容器停止运行,容器中的数据不再可用,里面的数据难以被其他容器重用。当容器被删除,当中的数据会一并消失
  • 容器中的数据与运行容器的环境紧耦合,难以被迁移
  • 往容器中的可写层写数据,需要通过storage driver管理文件系统,性能被削弱

为了解决上述问题,Docker提供了两种储存数据的方式:volumes和bind mounts,它们和容器松耦合,即使容器停止甚至被删除,这些数据依然得以保留。

我们所说的数据一般有两种状态:可变的和不变的,也称为动态数据和静态数据。

  • 动态数据 如数据库产生的数据,会随着时间的改变而改变
  • 静态数据 如网站的html文件等,发布后就不会改变的

静态数据保存在镜像层中是没有问题的,因为它们不变,因此我们可以把这些数据打包进镜像文件,但像数据库,我们就应该使用Docker提供的储存方案保存它们。

使用volumes

volumes是一个保存数据的目录,通常位于/var/lib/docker/volumes/目录下,并由Docker管理。其他非Docker进程不应该修改这个目录下面的数据。

volumes可以分为匿名volume和命名volume,除了名字不同外,它们的行为一致。

  • 匿名volume在容器运行的时候由Docker创建,每个匿名volume都有一个唯一的ID
  • 由于匿名volume没有名称,因此在挂载的时候不需要指定名称
  • 命名volume可以自己创建,也可以由Docker创建
  • 命名volume在挂载的时候需要指定名称

使用命名volume

volume是一个目录,位于/var/lib/docker/volumes下面,我们可以使用docker volume命令创建和管理这些volume。volume可以同时被多个容器挂载。

可以通过-v(--volume)参数或者--mount参数把volume挂载到容器中,不过需要注意的是:–mount参数在17.06版本之前只能够在swarm service环境中使用,17.06或之后的版本–mount也能够在非集群环境中挂载volume

以mysql镜像为例子,下面的例子创建了一个命名volume:

如果Docker发现指定名称的volume还不存在,会先帮我们创建出来。这个volume被映射到容器的/var/lib/mysql目录。

使用ls观察目录结构:

可以看到,mysql中的数据被存放到mysql这个volume的_data目录下面。

使用docker volume命令

docker volume命令有几个子命令,可以方便地创建和管理volumes。

之前的例子中的volume是由Docker创建的,现在我们通过docker volume create命令手动创建volume。

然后使用docker volume ls查看

创建好volume之后,可以像之前一样运行容器

无论是docker为我们创建volume还是我们使用docker volume create手动创建,它们的行为一致。

使用匿名volume

匿名volume的使用和命名volume一样,但是挂载的时候不需要指定名称,匿名volume只能够由Docker创建。

那么怎样知道容器挂载的是哪一个volume呢?可以使用docker inspect命令:

docker inspect命令用于查阅容器的元数据,其中就包括volume的使用信息。

挂载其他容器的volume

使用--volumes-from选项,可以从一个容器挂载另一个容器中的volume,非常适合在容器间共享数据。

使用--volumes-from选项挂载的volume挂载点都一样,这里是/var/lib/mysql

Data-Packed volume

data-packed volume类似上面的例子,也是从其他的容器挂载volume,不同的是,data-packed volume中的数据是镜像创建的过程中打包进去的,保存在镜像层,也就是说,data-packed volume中的数据适合放置静态数据。

然后其他容器就可以使用--volumes-from挂载这个容器提供的volumes。

删除volume

可以使用docker volume rm命令或者docker volume prune命令删除volume

  • rm用于删除指定volume,即使这些volume目前被某个容器引用
  • prune用于删除那些孤儿volume,即没有任何容器挂载的volume

使用bind mounts

和volumes不同,bind mounts可以挂载宿主机文件系统中的任意目录,bind mounts的随意性会造成一定的安全隐患,例如容器可以修改系统的重要文件。

挂载目录

开发人员在开发的过程中为了方便测试,可以把宿主机中的项目路径挂载进容器,这样容器就可以随时读取项目文件。下面的例子把java项目路径挂载进容器的tomcat目录。

挂载之后,在宿主机中对文件的任何修改都会马上反应在容器当中。

挂载文件

bind mounts方式不仅可以挂载目录,也可以把文件挂载进容器

例如把/etc/hosts文件挂载到容器

挂载文件的时候需要特别注意:如果要挂载的本地文件不存在,那么docker会自动帮你创建,但是,创建出来的是一个目录,而不是文件,如果不注意的话,很可能会造成错误。

总结

无论是volumes还是bind mounts,都有一些地方需要注意

  • 挂载volume进容器的时候,如果容器中的挂载点有数据,则会把这些数据复制到宿主机的挂载点中
  • volumes位置固定在/var/lib/docker/volumes下面,这是一个优点,也是一个缺点,优点是不会影响宿主机的文件系统,比较安全;缺点是失去了灵活性
  • 挂载bind mounts的时候,宿主机的目录会覆盖容器中的同名目录,结果是容器中的原数据不可见,直到bind mounts卸载
  • bind mounts可以是宿主机的任意目录,会造成一定的安全问题,但它非常灵活

使用共享储存设备

为了容错设计,应用和数据一般都不会放置在同一主机中,这就要求容器具备挂载远程volume的能力。但很遗憾,docker默认不具备这个能力,如果确实有这个需求,可以通过docker的插件实现,具体可参考官方链接:volume plugins

volumes位置固定的缺点限制了它的灵活性,但是volumes配合bind mounts却可以工作得很好,以glusterfs分布式文件系统为例子:

docker remote volume

docker remote volume

  • glusterfs服务器向外提供了data目录用于数据保存
  • Docker Host主机把这个远程data目录挂载到了自己的/mnt目录
  • Docker Host中使用其中一个容器以bind mounts的方式挂载本地/mnt目录,间接使用了远程目录
  • 其他容器通过–volumes-from的方式使用glusterfs client容器中的volume

转载请注明:Pure nonsense » Docker数据储存

喜欢 (0)
0 0 投票数
文章评分
订阅评论
提醒
guest
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x
()
x