Docker系列03—Docker 存储卷

一、存储卷介绍

1.1 背景

  1. Docker 的 AFUS 分层文件系统

  docker镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像层并在镜像栈顶部加一个读写层;

  如果运行的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件版本任然存在,只是已经被读写层中该文件的副本所隐藏,此即“写时复制(COW)”机制。

  1. 示意图

Docker系列03—Docker 存储卷

描述:如果一个文件在最底层是可见的,如果在layer1上标记为删除,最高的层是用户看到的layer2的层,处于layer0上的文件,在layer2上可以删除,但是只标记删除,用户是不可见的,总之在到达最顶层之前,把它标记删除,对于最上层的用户是不可见的,当标记一删除,只有在最上层建一个同名一样的文件,才是可见的。

1.2 为什么要使用存储卷

  对于这类操作,修改删除等,一般效率比较低,如果对于I/O要求比较高的应用,如redis在实现持久化存储时,是在底层存储时的性能要求比较高。

  假设底层运行一个存储库mysql,mysql本来对于I/O的要求就比较高,如果mysql又是运行在容器中自己的文件系统之上时,也就是容器在停止时,就意味着删除,除非现数据存取效率比较低,要避免这个限制要使用存储卷来实现。

  存在的问题:

  存储于联合文件系统中,不宜于宿主机访问;

  容器间数据共享不便

  删除容器其数据会丢失

1.3 存储卷

  1. “卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机上的某个目录“绑定(关联)”;

  类似于挂载一样,宿主机的/data/web目录与容器中的/container/data/web目录绑定,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器直接访问宿主机中的内容,也可以在宿主机向容器供给内容,两者是同步的。

  在宿主机上能够被共享的目录(可以是文件)被称为volume。

  1. 存储卷作用

  优点:容器中进程生成的数据,都保存在存储卷上,从而脱离容器文件系统自身后,当容器被关闭甚至被删除时,都不用担心数据被丢失,实现数据可脱离容器生命周期而持久,当再次重建容器时,如果可以让它使用到或者关联到同一个存储卷上时,再创建容器,容器不是之前的容器,但是数据还是之前的数据。特别类似于进程的运行逻辑,进程本身不保存任何的数据,数据都在进程之外的文件系统上,或是专业的存储服务上,所以进程每次停止,只是保存程序文件,对于容器也是一样;容器就是一个有生命周期的动态对象来使用,容器关闭就是容器删除的时候,但是它底层的镜像文件还是存在的,可以基于镜像再重新启动容器。

  但是容器有一个问题,一般与进程的启动不太一样,就是容器启动时选项比较多,如果下次再启动时,很容器会忘记它启动时的选项,所以最好有一个文件来保存容器的启动,这就是容器编排工具的作用。一般情况下,是使用命令来启动操作docker,但是可以通过文件来读,也就读文件来启动,读所需要的存储卷等,但是它也只是操作一个容器,这也是需要专业的容器编排工具的原因。

  另一个优势就是容器就可以不置于启动在那台主机上了,如几台主机后面挂载一个NFS,在各自主机上创建容器,而容器上通过关联到宿主机的某个目录上,而这个目录也是NFS所挂载的目录中,这样容器如果停止或者是删除都可以不限制于只能在原先的宿主机上启动才可以,可以实现全集群范围内调试容器使用,当再分配存储、计算资源时,就不会再局限于单机之上,可以在集群范围内建立起来,基本各种docker的编排工具都能实现此功能,但是后面严重依赖于共享存储的使用。

1.4 存储卷原理

  volume于容器初始化之时会创建,由base image提供的卷中的数据会于此期间完成复制

  volume的初意是独立于容器的生命周期实现数据持久化,因此删除容器之时既不会删除卷,也不会对哪怕未被引用的卷做垃圾回收操作

  卷为docker提供了独立于容器的数据管理机制

1.5 存储卷分类

Docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上位置有所不同;

  1. Bind mount volume (绑定挂载卷):在宿主机上的路径要人工的指定一个特定的路径,在容器中也需要指定一个特定的路径。关联两个路径

  2. Docker-managed volume (docker管理卷):只需要在容器内指定容器的挂载点是什么,而被绑定的宿主机下的那个目录,是由容器引擎daemon自行创建一个空的目录,或者使用一个已经存在的目录,与存储卷建立存储关系,这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定那些使用目录,临时存储比较适合。

Docker系列03—Docker 存储卷

二、使用存储卷

为 docker run 命令使用 -v 选项即可使用 volume

Bind-mount volume (绑定挂载卷):

[root@docker ~]# docker run -d -it --name busybox01 -v /data/busybox:/data busybox:latest
# 宿主机目录:容器目录
# 将容器里面的/data目录挂载到宿主机的/data/busybox目录 [root@docker ~]# docker inspect -f {{.Mounts}} busybox01
[{bind /data/busybox /data true rprivate}]
# 查看挂载情况

Docker-managed volume (docker管理卷)

[root@docker ~]# docker run -d -it --name busybox_2 -v /data/busybox_m busybox:latest
# 容器目录
[root@docker ~]# docker inspect -f {{.Mounts}} busybox_2
[{volume b670ec29f1d5066605e11be7732162687049178b9995195e4e42abe5ba9a7e12 /var/lib/docker/volumes/b670ec29f1d5066605e11be7732162687049178b9995195e4e42abe5ba9a7e12/_data /data/busybox_m local true }]

两者在容器被删除后,文件依旧保存

2.1 使用 Bind-mount volume (绑定挂载卷)

  1. 创建容器busybox01

[root@docker ~]# docker run -d -it --name busybox01 -v /data/volumes/busybox01:/data busybox:latest

# 注:要是宿主机的目录不存在,则创建
  1. 查询存储卷信息

[root@docker ~]# docker inspect -f {{.Mounts}} busybox01
[{bind /data/volumes/busybox01 /data true rprivate}]
  1. 在宿主机的存储卷上进行简单的操作

[root@docker ~]# echo "This is a test for delete 01" > /data/volumes/busybox01/index.html
  1. 进入容器验证

[root@docker ~]# docker exec -it busybox01 /bin/sh
/ # cat /data/index.html
This is a test for delete 01

  5. 验证数据持久性

  删除容器,启动新容器,挂载原目录

[root@docker ~]# docker rm -f busybox01
busybox01
[root@docker ~]# docker run -d -it --name busybox01.1 -v /data/volumes/busybox01:/data busybox:latest
[root@docker ~]# docker exec -it busybox01.1 /bin/sh
/ # cat /data/index.html
This is a test for delete 01

  6. 多个容器同时关联同一个宿主机目录

[root@docker ~]# docker run -d -it --name busybox02 -v /data/volumes/busybox01:/data busybox:latest
[root@docker ~]# docker exec -it busybox02 /bin/sh
/ # cat /data/index.html
This is a test for delete 01

  7. 在宿主机中修该文件内容

[root@docker ~]# echo "This is a test for insert" >> /data/volumes/busybox01/index.html
[root@docker ~]# docker exec -it busybox02 /bin/sh
/ # cat /data/index.html
This is a test for delete 01
This is a test for insert

2.2 使用docker-managed volume (docker管理卷)

  1. 创建容器 busybox10

[root@docker ~]# docker run -d -it --name busybox10 -v /data busybox:latest

  2. 查看存储卷情况

[root@docker ~]# docker inspect busybox10   # 查询全部
[
{
"Id": "a19a7b24863ead76c5be3d13ec11c2399bb725579b3b8d06422d5eeb5579d307",
"Created": "2020-04-02T11:36:11.917365309Z",
"Path": "sh",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 30402,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-04-02T11:36:12.119386651Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:83aa35aa1c79e4b6957e018da6e322bfca92bf3b4696a211b42502543c242d6f",
"ResolvConfPath": "/var/lib/docker/containers/a19a7b24863ead76c5be3d13ec11c2399bb72
..................................

[root@docker ~]# docker inspect -f {{.Mounts}} busybox10
# 精确查询
[{volume 4b908787e981e0481cf9f5a520275c1467f662ffb3957f3d15d8e46d8b9b2b43 /var/lib/docker/volumes/4b908787e981e0481cf9f5a520275c1467f662ffb3957f3d15d8e46d8b9b2b43/_data /data local true }]

  3. 在宿主机的存储卷目录添加内容

[root@docker ~]# echo "This is a test for mount" > /var/lib/docker/volumes/4b908787e981e0481cf9f5a520275c1467f662ffb3957f3d15d8e46d8b9b2b43/_data/index.html

  4. 进入容器验证,并修改文件内容

[root@docker ~]# docker exec -it busybox10 /bin/sh
/ # cat /data/index.html
This is a test for mount
/ # echo "yes" >> /data/index.html

  5. 在宿主机上验证

[root@docker ~]# cat /var/lib/docker/volumes/4b908787e981e0481cf9f5a520275c1467f662ffb3957f3d15d8e46d8b9b2b43/_data/index.html
This is a test for mount
yes

2.3 volumes-from 基于已有容器的存储器,创建容器

  1. 先创建一个容器

[root@docker ~]# docker run -d -it --name busybox -v /data/volumes/busybox:/data/busybox busybox:latest
[root@docker ~]# docker exec -it busybox /bin/sh
/ # echo " T=T " > /data/busybox/index.html

  

  2. 基于原有的容器启动

[root@docker ~]# docker run -d -it --name busybox_mount --network container:busybox --volumes-from busybox busybox:latest
[root@docker ~]# docker exec -it busybox_mount /bin/sh
/ # cat /data/busybox/index.html
T=T

  3. 查看挂载信息

[root@docker ~]# docker inspect -f {{.Mounts}} busybox_mount
[{ /data/volumes/busybox /data/busybox true rprivate}]

三、Volume 删除和孤单 volume 清理

3.1 在删除容器时删除volume

A. Bind-mount volume (绑定挂载卷)

可以使用docker rm -v 命令在删除容器时删除该容器的卷

  1. 创建新的容器

[root@docker ~]# docker run -d -it --name busybox_01 -v /data/volumes/del_mount/busybox_01:/data/ busybox:latest
7f5a6cab30ecc04a11c1a77a6a337d72732e164711a41d288f24f3079f063b76
[root@docker ~]# echo "this is a test" > /data/volumes/del_mount/busybox_01/index.html
[root@docker ~]# docker exec -it busybox_01 /bin/sh
/ # cat /data/index.html
this is a test

  2. 使用docker rm -v 删除容器及卷

[root@docker ~]# docker stop busybox_01      # 先停止容器
[root@docker ~]# docker rm -v busybox_01
busybox_01
[root@docker ~]# cat /data/volumes/del_mount/busybox_01/index.html
this is a test

?????唉,气不气,绑定挂载卷没有用 #_#

B. docker-managed volume (docker管理卷)

  

  1. 创建容器

[root@docker ~]#  docker run -d -it --name busybox_02 -v /data/ busybox:latest
792f5303302264dba913c7c1b6d81ebd59a3db695835a9f1a8be97c0ca0f70bc

[root@docker ~]# docker volume ls
DRIVER VOLUME NAME
local d19467ea5a0c3428d2e77b414607775b17ac2071805cf5501f81bec81d3d1609
local ac2071805d1609cf5501f81becd19467ea5a0c3428d2e77b414607775b1781d3

[root@docker ~]# docker stop busybox_02
web2

[root@docker ~]# docker rm -v busybox_02
web2

[root@docker ~]# docker volume ls
DRIVER VOLUME NAME
local ac2071805d1609cf5501f81becd19467ea5a0c3428d2e77b414607775b1781d3

 

3.2 批量删除孤单的volumes

[root@docker ~]# docker volume rm $(docker volume ls -qf dangling=true)
# docker volume rm 名称 为删除某一个volume
# docker volume ls -qf dangling=true 列举孤单的volume
[root@docker ~]# docker volume ls
DRIVER VOLUME NAME

四、总结

卷有两种,两种,两种,两种,,,,

挂载卷-管理卷

上一篇:怎样配置spring aop


下一篇:初学ios遇到问题记录01