为什么需要存储卷?
- Docker镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像并在镜像栈顶部添加一个读写层。
- 如果运行的容器修改了一个已有的文件,那么该文件会从只读层复制到读写层,该文件的只读版本依然存在,只是已经被读写层中该文件的副本所隐藏,即“写时复制 COW”机制。
存在的问题
存储于联合文件系统中,不易于宿主机访问;
容器间数据共享不便;
删除容器其数据会丢失
存储卷 volume
“卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机上的某个目录“绑定(关联)”;
类似于挂载一样,宿主机 /data/web目录与容器中的/container/data/web目录建立绑定关系,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系, 宿主机和容器内可以共享数据库内容,让容器直接访问宿主机中的内容,宿主机也可以访问容器内容,两者是同步的。即使容器被删除,数据也不会丢失。
数据卷的最大特点是:其生存周期独立于容器的生存周期
- volume于容器初始化之时会创建,由base image提供的卷中的数据会于此期间完成复制
- volume的初衷是独立于容器的生命周期实现数据持久化,因此删除容器之时既不会删除卷,也不会对哪怕未被引用的卷做垃圾回收操作
- 卷为docker提供了独立于容器的数据管理机制
Docker卷类型
Docker存储卷有两种类型,每种类型都在容器中存在一个挂载点,但其在宿主机上位置有所不同
第一种:绑定挂载卷: 在宿主机上的路径需要人工指定,在容器中的路径也需要指定,两个已知的路径建立关联关系。
第二种:docker管理卷: 只需要指定容器的挂载点,而被绑定宿主机下的那个目录,是由容器引擎daemon自行创建一个空的目录,或者使用一个已经存在的目录,与存储卷建立存储关系,这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定那些使用目录,临时存储比较适合
在容器中使用volumes
1.docker管理卷
在一个终端运行容器:
docker run -it --name vbox1 -v /data busybox
/ # touch /data/test
另一个终端查看:
docker inspect vbox1 #查看容器详细信息
"Mounts": [
{"Type": "volume",
"Name": "257ff9d7f0822606560fc21f8bd63b784cd2db72e410c8634ef361df3f5157b3",
"Source": "/var/lib/docker/volumes/257ff9d7f0822606560fc21f8bd63b784cd2db72e410c8634ef361df3f5157b3/_data",
"Destination": "/data",
# cd /var/lib/docker/volumes/257ff9d7f0822606560fc21f8bd63b784cd2db72e410c8634ef361df3f5157b3/_data
# ls
test
# echo "hello" > a.txt #在容器中也可看到
2.绑定挂载卷
docker run -it --rm --name vbox2 -v /host/volumes/b2:/data busybox
docker inspect vbox2
"Mounts": [
{"Type": "bind",
"Source": "/host/volumes/b2",
"Destination": "/data",
在宿主机/host/volumes/b2 做的操作和容器内/data的操作会同步。下次启动容器绑定挂在此卷时,文件依然存在。
使用golang模板查看
docker inspect -f {{.Mounts}} vbox2
[{bind /host/volumes/b2 /data1 true rprivate}]
docker inspect -f {{.NetworkSettings.Networks.bridge.IPAddress}} vbox2
172.17.0.5
多个容器共享同一个存储卷
可以让两个docker容器同时关联到同一个宿主机的目录中,实现共享使用同一个存储卷,容器之间的数据共享
docker run -it --rm --name vbox3 -v /host/volumes/b2:/data3 busybox
# ls /data3
docker run -it --rm --name vbox2 -v /host/volumes/b2:/data2 busybox
# ls /data2
复制存储卷 --volumes-from
当需要多个容器同进使用多个卷,卷在那里写每次初始化时都要使用-v来指定,如果不想记录这个路径,docker还支持复制其他的存储卷路径
制定一个容器,不执行任何任务,创建时,只要指定它的存储路径,作为其他容器的基础容器,其他的容器启动时去复制它的存储卷设置,但是这样的点浪费,不过使用joined container的基础的话,几个容器本来就有密切的关系,如nginx+tomcat,nginx的容器和tomcat容器共享一个底层的网络,有一个对外的接口,有一个loop接口,这样80给nginx,在内loop给tomcat,请求进来,nginx作为反射代理转给tomcat就可以了,再加一个mysql,即可实现一个NMT架构。 让它们共享名称空间中的uts,net,ipc, 还可以共享存储卷,ngInx处理静态,tomcat处理动态的,在同一个目录下,使用存储卷来解决这个问题,这种组织方式使用构建应用。
nginx tomcat mysql
共享uts,net,ipc
共享volume
docker run -it --rm --name vbox4 --volumes-from vbox2 busybox
# ls data1/
b.txt vbox2 vbox3
制定基础镜像(网上有专门制作基础架构容器的,不用启动,只要创建就可以了)
# docker run --name infracon -it --rm -v /data/basic/volume/:/data/web/html busybox
# docker run --name nginx --network container:infracon --volumes-from infracon -it busybox #加入网络名称空间,同时复制卷