Docker镜像是基于联合文件系统(Union File System)的一种层式结构,由一系列指令一步一步构建出来。
Docker镜像被存储在一系列的只读层中。当我们创建一个容器时,Docker会读取镜像(只读),并在其顶部添加一层读写层。如果正在运行中的容器修改了现有文件,该文件将会被拷贝出底层的只读层,放到最顶层的读写层中。读写层中原来的旧版本文件(未被更改过的文件)仍然存在于镜像中。所以当Docker容器被删除后,再基于原来的镜像创建容器时,将创建一个没有任何数据更改的容器,在之前那个容器中的数据更改会丢失掉。
为什么需要Volume
为了能够持久化这些更改过的数据,并且能够很容易实现容器间共享数据,Docker提出了Volume的概念。Volume是外部默认的联合文件系统或者是存在于宿主文件系统中正常的文件或文件夹。
数据卷可以带来以下好处:
- Volume可在容器之间共享或重用数据;
- Volume的更改可以直接生效;
- Volume的生命周期一直持续到没有容器使用它为止;
- 对Volume操作不会影响到镜像本身;
- Volume可以完成容器到宿主机、宿主机到容器以及容器到容器之间的数据共享。
Docker volume 有如下几种形态:
不使用 Docker volume
默认情况下,容器不使用任何 volume,此时,容器的数据被保存在容器之内,它只在容器的生命周期内存在,会随着容器的被删除而被删除。当然,也可以使用 docker commit 命令将它持久化为一个新的镜像。
Data volume (数据卷)
一个 data volume 是容器中绕过 Union 文件系统的一个特定的目录。它被设计用来保存数据,而不管容器的生命周期。因此,当你删除一个容器时,Docker 肯定不会自动地删除一个volume。有如下几种方式来使用 data volume:
(1)使用 “-v 容器内目录” 形式
docker run -d -v /data centos /bin/bash |
---|
使用 docker inspect 命令可以看出,Docker 将本地一个 _data 目录 mount 为容器内的 data目录了:
"Mounts": [ { "Type": "volume", "Name": "b9697411cd69fde3b5fe471229fc02e70409f8e84edd3333765f441cfb5961f8", "Source": "/var/lib/docker/volumes/b9697411cd69fde3b5fe471229fc02e70409f8e84edd3333765f441cfb5961f8/_data", "Destination": "/data", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], |
---|
这种情况当容器被删除后,
/var/lib/docker/volumes/b9697411cd69fde3b5fe471229fc02e70409f8e84edd3333765f441cfb5961f8/_data
目录及其中的内容都还会保留下来,但是,新启动的容器无法再使用这个目录,也就是说,已有的数据不能自动地被重复使用了。
(2)使用 -v 来挂载一个主机上的目录到容器的目录
docker run -d -v /root/data:/data centos /bin/bash |
---|
主机上的目录可以是一个本地目录,也可以在一个 NFS share 内,或者在一个已经格式化好了的块设备上。
其实这种形式和第一种没有本质的区别,容器内对 /data的操作都会反映到主机上的 /root/data 目录内。只是,重新启动容器时,可以再次使用同样的方式来将 /root/data 目录挂载到新的容器内,这样就可以实现数据持久化的目标。
使用 docker volume 命令
Docker 新版本中引入了 docker volume 命令来管理 Docker volume。
(1)使用默认的 ‘local’ driver 创建一个 volume
docker volume create --name myvolume |
---|
查看结果:
# docker volume inspect myvolume[ { "CreatedAt": "2021-04-09T18:39:05 08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/myvolume/_data", "Name": "myvolume", "Options": {}, "Scope": "local" }] |
---|
(2)使用这个 volume
docker run -d --name mycentos -v myvolume:/data centos /bin/bash |
---|
结果将 myvulume 对应的主机上的目录挂载给容器内的 /data 目录。
"Mounts": [ { "Type": "volume", "Name": "myvolume", "Source": "/var/lib/docker/volumes/myvolume/_data", "Destination": "/data", "Driver": "local", "Mode": "z", "RW": true, "Propagation": "" } ], |
---|
删除 volume
可以使用 docker rm -v 命令在删除容器时删除该容器的卷。
docker rm -vf mycentos |
---|
批量删除volume
从上面的介绍可以看出,使用 docker run -v 启动的容器被删除以后,在主机上会遗留下来孤单的卷。可以使用下面的简单方法来做清理:
docker volume rm $(docker volume ls -qf dangling=true) |
---|