1 概述
容器的数据存放在最上层的读写层。
Docker镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像层并在镜像栈顶部添加一个读写层
如果运行的容器修改了现有的一个已经存在的文件,那该文件就会从读写层下面的只读层复制到读写层,该文件的只读版本依然存在,只是已经被读写层中该文件的副本所隐藏,为“写时复制”机制
联合挂载解决了镜像分发问题,但是导致性能损耗,
关闭并重启容器,其数据不受影响;但删除Docker容器,则其更改将会全部丢失
存在以下三个问题
.存储于联合文件系统中,不易于宿主机访问;
.容器间数据共享不便
.删除容器其数据会丢失
解决方案:使用“卷(volume)” ,卷是容器上的一个或者多个“目录”,此类目录可绕过联合文件系统,与宿主机的某个目录“绑定”,使得数据脱离容器而存在,容器删除后,数据依然存在。
每一个挂载点称为卷,这里的挂载是用来挂载目录的(bind,目录挂目录)。
一个卷用来绑定一个目录,一个容器可以定义多个卷
卷关联宿主机上的某一路径,卷和联合挂载不一样,优于联合挂载
卷实现了数据的持久化
卷为docker提供了独立于容器的数据管理机制
.可以把 “镜像 ”想像成静态文件,例如 “程序 ”,把卷类比为动态内容,例如 “数据 ”;于是,镜像可以重用,而卷可以共享;
.卷实现了 “程序 (镜像 )”和“数据 (卷)”分离,以及 “程序 (镜像 )”和“制作镜像的主机 ”分离,用户制作镜像时无须再考虑镜像运行的容器所在的主机的环境;
2 卷的类型
卷有两种类型:
Docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上的位置有所不同;
1:绑定挂载卷:由用户指定宿主机的路径,需要人工创建好宿主机的目录。
2:docker管理的卷:docker路径不需要创建,docker进程会自动生成该路径。
-f后是json格式的字典,查看分段格式的标志
为docker run命令使用-v选项即可使用Volume,指定-v选项指定卷路径,为docker run命令使用-v选项即可使用Volume
2.1 docker管理的卷
例子如下:
docker run -it --name bbox1 –v /data busybox
查看 bbox1容器的卷、卷标识符及挂载的主机目录
docker inspect -f {{.Config.Volumes}}{{.Mounts}} bbox1
可以用docker volume ls查看卷的名称,在用docker volum inspect 卷名称 来查看具体卷的信息
docker volume inspect 737432382e1292b2aa828f6e66f04721bf251dbeaa082b295f5bc08bf5ac6c60
找到的路径为本地的宿主机的路径
这个方式,可以直接在宿主机部署站点,直接把站点放到容器对应的目录本地。
2.2 绑定挂载卷例子
格式
docker run -it -v HOSTDIR:VOLUMEDIR --name sunny02 busybox
以下HOSTDIR:VOLUMEDIR表示宿主机路径:卷路径,因此宿主机要先创建对应要挂载的目录
如这里创建宿主机目录如下
mkdir -pv /docker/data/volumes/sunny
启动容器
docker run -it --name sunny02 -v /docker/data/volumes/sunny:/data/htdocs --rm busybox:1.27.2 docker inspect -f {{.Mounts}} sunny02
结果如下
[{bind /docker/data/volumes/sunny /data/htdocs true rprivate}]
bind表示绑定挂载卷
此时,路径就是宿主机的/docker/data/volumes/sunny
如果路径不需要管理就使用docker生成的卷,如果需要管理,就用绑定挂载卷
这里,如果启动的镜像本来就存在/data/htdocs,即绑定挂载点本身有数据,新容器的挂载点启动后,挂载目录也是/data/htdocs,这个时候如果再次挂载到这个目录,则原来镜像里的/data/htdocs数据不可见,已经被隐藏
例子如下
首先先制作一个镜像
先启动容器,并创建/data/htdocs和/data/htdocs目录下生成hello文件
[root@docker ~]# docker run -it --name sunny02 --rm busybox:1.27.2 / # ls bin dev etc home proc root sys tmp usr var / # mkdir /data/htdocs mkdir: can't create directory '/data/htdocs': No such file or directory / # mkdir -p /data/htdocs / # cd /data/htdocs/ /data/htdocs # ls /data/htdocs # echo "hello sunny" > hello /data/htdocs # ls hello /data/htdocs #
环境准备好了,制作成镜像
-a指明作者,-m备注,-p暂停容器时制作镜像,即镜像为当前的容器状态,testbox:sunnyv1为当前标签,-c改变容器默认的启动命令
docker commit -a "sunny" -m "sunny test" -p sunny02 testbox:sunnyv1
基于镜像testbox:sunnyv1来启动容器
先指定挂载点,此时容器有/data/htdocs这个目录,且文件hello存在
[root@docker ~]# docker run -it --name sunny03 --rm testbox:sunnyv1 / # ls bin data dev etc home proc root sys tmp usr var / # cd /data/ /data # ls htdocs /data # cd htdocs/ /data/htdocs # ls hello /data/htdocs #
然后,指定挂载点,做对比区别
先创建宿主机目录
mkdir -pv /docker/data/volumes/sunny02
指定挂载点后启动容器
[root@docker ~]# docker run -it --name sunny02 -v /docker/data/volumes/sunny02:/data/htdocs --rm testbox:sunnyv1 / # ls bin data dev etc home proc root sys tmp usr var / # cd /data/ /data # ls htdocs /data # cd htdocs/ /data/htdocs # ls /data/htdocs #
如果宿主机的挂载目录/docker/data/volumes/sunny02有文件,则挂载后的容器依然是可以看到/docker/data/volumes/sunny02的数据,但是原来镜像 testbox:sunnyv1的/data/htdocs下的文件已经不可见,被隐藏了,和路径挂载一样。因此挂载时,要注意镜像的路径,不要隐藏掉镜像需要使用的目录数据
3 共享卷
有两种方式可以在容器间共享卷:
1..多个容器的卷使用同一个主机目录,例如,以下两个容器都使用宿主机的目录 /docker/volumes/v1作为数据盘
docker run –it --name c1 -v /docker/volumes/v1:/data busybox docker run –it --name c2 -v /docker/volumes/v1:/data busybox
.复制使用其它容器的卷,为 docker run命令使用 --volumes-from选项
如下例子,先启动了容器 bbox1,挂载本地 /docker/volumes/v1作为卷目录,再启动容器bbox2,直接复制bbox1的卷作为其容器的卷
docker run -it --name bbox1 -v /docker/volumes/v1:/data busybox docker run -it --name bbox2 --volumes-from bbox1 busybox
复制卷,有一个好处是实现共享,有个场景为,假设要挂载的卷很多,新生成的容器要一一挂载相同的宿主机目录,很麻烦,而且挂载路径可能出错,因此可以启动一个容器,不跑程序,仅用于挂载卷,相当于模板,后期要使用这个卷的数据的容器,都可以通过 --volumes-from来直接挂载对应的卷,保证卷的数据和目录都是一致的。这个容器
为基础架构容器,不做其他操作,仅提供卷的复制
一个容器可以使用多个卷,只需要用多个-v来指定即可
如下例子,同时指定两个卷/docker/data/volumes/sunny02 和 /docker/data/volumes/sunny
[root@docker volumes]# docker run -it --name c6 -v /docker/data/volumes/sunny:/data/htdocs -v /docker/data/volumes/sunny02:/data/html busybox / # ls bin data dev etc home proc root sys tmp usr var / # cd data /data # ls htdocs html
这个也是为什么,复制卷的时候,要用参数 --volumes-from,因为可能存在多个卷挂载的情况
注意,删除容器默认不会删除相关的卷 ,生产环境,建议不要删除卷,因为一旦把卷删除,相关数据也会丢失。