[docker](七)docker -- 数据卷

2019-12-03 09:36:12 浏览数 (1)

Docker的镜像是由一系列的只读层组合而来的,当启动一个容器时,Docker加载镜像的所有只读层,并在最上层加入一个读写层。这个设计使得Docker可以提高镜像构建、存储和分发的效率,节省了时间和存储空间,然而也存在如下问题:

  • 容器中的文件在宿主机上存在形式复杂,不能在宿主机上很方便地对容器中的文件进行访问。
  • 多个容器之间的数据无法共享。
  • 当删除容器时,容器产生的数据将丢失。

为了解决这些问题,Docker引入了数据卷(volume)机制。volume是存在于一个或多个容器中的特定文件或文件夹,这个目录以独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久化提供以下便利:

  • volume在容器创建时就会初始化,在容器运行时就可以使用其中的文件。
  • volume能在不同的容器之间共享和重用。
  • 对volume中数据的操作会马上生效。
  • 对volume中数据的操作不会影响到镜像本身。
  • volume的生存周期独立于容器的生存周期,即使删除容器,volume仍然会存在,没有任何容器使用的volume也不会被Docker删除。

Docker供了volume driver接口,通过实现该接口,我们可以为Docker容器提供不同的volume存储支持。当前官方默认实现了local这种volume driver,它使用宿主机的文件系统为Docker容器提供volume。

数据卷的使用方式

为容器添加volume,类似于Linux的mount操作,用户将一个文件夹作为volume挂载到容器上,可以很方便地将数据添加到容器中供其中的进程使用。多个容器可以共享同一个volume,为不同容器之间的数据共享提供了便利。

1、创建volume

代码语言:txt复制
   # 用户可以使用docker volume create创建一个volume,以下命令创建了一个指定名字的volume
   $sudo docker volume create-name vol_simple
   
   # 用户在使用docker run或docker create创建新容器时,也可以使用一v标签为容器添加volume,以下命令创建了一个随机名字的volume,并挂载到容器中的/data目录下。
   $sudo docker run -d -v /data ubuntu /bin/bash
   
   # 使用docker volume inspect命令可以获得该volume包括其在宿主机中该文件夹的位置等信息。
   $sudo docker volume inspect vol_simple
   {
   "Name":"vol_ simple",
   "Driver":"local",
   "Mountpoint":"/var/lib/docker/volumes/vol_simple/_data"
   }

2、挂载volume

代码语言:txt复制
   # 除了上面创建volume时使用的挂载方式之外,Docker同时也允许我们将宿主机上的目录挂载到容器中。
   $sudo docker run -v /host/dir:/container/dir ubuntu /bin/bash

3、使用Dockerfile添加volume

代码语言:txt复制
   # 使用VOLUME指令向容器添加volume
   VOLUME /data
   # 在使用docker build命令生成镜像并且以该镜像启动容器时会挂载一个volume到/data。与上文中vol_ simple例子类似,如果镜像中存在/data文件夹,这个文件夹中的内容将全部被复制到宿主机中对应的文件夹中,并且根据容器中的文件设置合适的权限和所有者。

4、共享volume(--volume-from)

代码语言:txt复制
   # 在使用docker run或docker create创建新容器时,可以使用--volumes-from标签使得容器与已有的容器共享volume 
   $sudo docker run --rm --it --name vol_use --volumes-from vol_simple ubuntu /bin/bash

5、删除volume

如果创建容器时从容器中挂载了volume,在/var/lib/docker/volumes下会生成与volume对应的目录,使用docker rm删除容器并不会删除与volume对应的目录,这些目录会占据不必要的存储空间,可以手动删除,因为有些随机生成的目录名称是无意义的随机字符串,要知道它们是否与未被删除的容器对应也十分麻烦。所以在删除容器时需要对容器的volume妥善处理。在删除容器时一并删除volume有以下3种方法:

  • 使用docker volume rm <volume_name>删除volume。
  • 使用docker rm -v <container_name>删除容器。
  • 在运行容器时使用docker run --rm,--rm标签会在容器停止运行时删除容器以及容器所挂载的volume。

6、备份、恢复或迁移volume

代码语言:txt复制
   # 备份volume可以使用以下方法。
   $sudo docker run --rm --volumes-from vol_simple -v $(pwd):/backup ubuntu tar cvf /backup/data.tar /data
   
   # 恢复volume可以使用以下方法。
   $sudo docker run --it --name vol_bck -v /data ubuntu /bin/bash
   $sudo docker run --rm --volumes-from vol_bck -v $(pwd):/backup ubuntu tar xvf /backup/data.tar -C /
数据卷原理解读

前面已经提到,Docker的volume的本质是容器中一个特殊的目录。在容器的创建过程中,Docker会将宿主机上的指定目录(一个以volume ID为名称的目录,或者指定的宿主机目录)挂载到容器中指定的目录上,这里使用的挂载方法是绑定挂载(bind mount ),故挂载完成后的宿主机目录和容器内的目标目录表现一致。

所以,Docker daemon在为容器挂载目录的过程中着重处理的事情就是是如何组装出合适的mount指令,而在源码中,挂载点这个结构体中则包含了组装mount命令所有需要的信息。

1、创建volume

  • 解析参数并生成参数列表,每一个参数描述了一个volume和容器的对应关系或是一个容器与其他容器共享volume的情况。
  • 初始化并使用参数列表中的参数生成挂载点列表,这一过程在创建容器时执行,即在宿主机和容器文件目录下创建上述挂载点中所需的路径。
  • 将挂载点列表传递给libcontainer,按照挂载点列表中指定的路径、mount参数、读写标志执行所有的mount操作,完成从宿主机到容器内挂载点的映射,这一过程在容器启动时才会执行。

2、删除volume

删除volume主要有前面提到的两种方法,第一,使用docker volume rm命令进行删除,第二,使用docker run --rm和docker rm -v在删除容器时删除所关联的volume。

使用第一种方式删除volume时,Docker首先会检查是否还有容器在使用这个volume,如果这个volume还被其他容器所使用,则返回错误信息,并终止删除。如果没有容器在使用这个volume ,那么Docker将这个volume在宿主机上对应的目录删除,并删除其维护的本地volume列表中的相关信息。

在使用第二种方式进行volume删除时,其volume的删除过程与第一种类似,不过需要注意的是,这种删除的方式会过滤掉挂载点中Named字段为true的volume,也就是说这种方式并不会对命名的volume进行删除。

3、volume相关配置文件

Docker的每个容器在/var/lib/docker/containers文件夹下有一个以容器ID命名的子文件夹,这个子文件夹中的config.json文件是这个容器的配置文件,可以从中看到这个容器所使用的volumeID以及它们的可写情况。如果你要查看volume的具体信息,你可以在/var/lib/docker/volumes文件夹下找与volume ID或者volume名字命名的子文件夹,这个子文件夹中的data目录存储了该volume中的所有内容。

0 人点赞