Docker数据卷详解:概念、使用方法及三种类型对比
Docker数据卷详解:概念、使用方法及三种类型对比
Docker数据卷是Docker容器中用于持久化存储数据的重要机制。本文将详细介绍Docker数据卷的基本概念、使用方法以及不同类型数据卷的挂载方式。通过具体的命令示例和挂载信息查询,帮助读者全面理解Docker数据卷的使用场景和特点。
一、Docker数据卷是什么
当删除Docker容器时,容器内部的文件也会随之销毁。在生产环境中,我们需要将数据持久化保存,因此产生了将容器内部的数据保存在宿主机的需求。Docker数据卷(Volume)就是为了解决以下问题而设计的:
- 容器与主机之间、容器与容器之间共享文件
- 容器中数据的持久化
- 容器中的数据备份、迁移、恢复
二、Docker数据卷的使用方法
在执行docker run
命令时,可以使用-v
参数来指定数据卷,完成数据卷挂载。数据卷可以是命名的,也可以是匿名的。匿名卷会被赋予一个随机名称,该名称保证在给定的Docker主机内是唯一的。与命名卷一样,即使删除使用它们的容器,匿名卷也会保留下来,除非在创建容器时使用了--rm
标志,在这种情况下与容器关联的匿名卷将被销毁。
匿名数据卷的使用
在启动容器时只指定容器内部的路径,不写宿主机路径。例如:
docker run -d -p 8888:80 -v /usr/share/nginx/html --name nginx-volume nginx:latest
使用docker inspect
命令查看其挂载信息:
docker inspect nginx-volume | grep -A 11 "Mounts"
输出结果:
"Mounts": [
{
"Type": "volume",
"Name": "538688015ecc44b37c36861c07bff24f7330b06a2d8dd396d4980a9594de461d",
"Source": "/var/lib/docker/volumes/538688015ecc44b37c36861c07bff24f7330b06a2d8dd396d4980a9594de461d/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
通过查询挂载信息可知,该容器挂载了一个名称为一段哈希串的volume类型的,其在宿主的存储位置在:/var/lib/docker/volumes/538688015ecc44b37c36861c07bff24f7330b06a2d8dd396d4980a9594de461d/_data
目录下,挂载的是容器内的路径:/usr/share/nginx/html
命名数据卷的使用
在启动容器时指定卷名,并绑定容器内部的路径。例如:
docker run -d -p 8800:80 -v nginx_dir:/usr/share/nginx/html --name nginx-volume2 nginx:latest
使用docker inspect
命令查看其挂载信息:
docker inspect nginx-volume2 | grep -A 11 "Mounts"
输出结果:
"Mounts": [
{
"Type": "volume",
"Name": "nginx_dir",
"Source": "/var/lib/docker/volumes/nginx_dir/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
通过查询挂载信息可知,该容器挂载了一个名称为nginx_dir
的volume类型的,其在宿主的存储位置在:/var/lib/docker/volumes/nginx_dir/_data
目录下,挂载的是容器内的路径:/usr/share/nginx/html
通过这两个示例发现,不管是命名数据卷还是匿名数据卷,其存储位置都在/var/lib/docker/volumes/<数据卷名称>/_data
目录下,且挂载类型均为volume
。那还有没有其他的类型的数据卷挂载吗?或者说,是否可以将数据存储到宿主机的其他位置?比如,希望将容器nginx-volume3
的目录指定到/home/lemon/docker_nginx_data/
目录之下,因为/var/lib/docker
目录存储在/
根分区下,其存储空间太小,希望将数据挪动到更大的目录/home
分区下。下面将介绍其他的两种类型文件绑定方式。
三、Docker存储的三种类型
如果希望将容器nginx-volume3
的目录/usr/share/nginx/html
指定到/home/lemon/docker_nginx_data/
目录之下,就需要使用如下的方式去指定挂载:
-v /home/lemon/docker_nginx_data:/usr/share/nginx/html
示例如下:
docker run -d -p 8801:80 -v /home/lemon/docker_nginx_data:/usr/share/nginx/html --name nginx-volume3 nginx:latest
使用docker inspect
命令查看其挂载信息:
docker inspect nginx-volume3 | grep -A 11 "Mounts"
输出结果:
"Mounts": [
{
"Type": "bind",
"Source": "/home/lemon/docker_nginx_data",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
通过查询挂载信息可知,该容器将宿主机的/home/lemon/docker_nginx_data
目录与容器的/usr/share/nginx/html
挂载了起来。与上面的两个类型相比较,我们发现其Type
参数类型为bind
,与上面的两种方式的volume
类型不同。
volume与bind两种类型优缺点对比
对比项 | Volume(卷) | Bind(绑定挂载) |
---|---|---|
存储位置 | Docker统一管理,默认存放在 /var/lib/docker/volumes/ | 直接使用宿主机上的指定目录 |
创建方式 | 通过 docker volume create 创建,Docker负责管理 | 需要手动指定宿主机路径 |
适用场景 | 推荐用于持久化存储,如数据库、日志等 | 适用于开发环境,可直接访问宿主机文件 |
容器间共享 | 容易共享,多个容器可以挂载同一个Volume | 手动管理,需要确保宿主机目录存在 |
安全性 | 更安全,容器无法直接访问宿主机 | 风险较高,容器可能影响宿主机数据 |
性能 | 一般更快,Docker进行了优化 | 可能受文件系统性能影响 |
跨平台 | 可以跨主机(NFS等),便于迁移和备份 | 仅限本地,受宿主机文件系统影响 |
此外,bind类型会存在空挂载的问题。例如,上面的容器nginx-volume3
在浏览器中访问时,会发现该容器无法访问Nginx的欢迎页。具体原因出现在空挂载上,如果bind类型挂载的宿主机路径为空,则会将容器内的挂载路径变为空。该特性适用于将宿主机上的配置文件替换容器内部的配置文件,也在一定程度上适用与容器文件迁移或者文件备份,但是前提条件迁移的目标地址最好是相同的宿主机系统,例如Linux系统迁移至Linux,Windows系统迁移至Windows。跨系统迁移会在一定程度上可能导致文件不能使用。
除了bind类型以外,还有一个不太常用的tmpfs类型,用于将容器内的路径指定到宿主机的内存上,通常用于一些高性能的文件读写环境下,例如将MySQL的数据库指定到内存当中,以增加缓存刷盘速度,或者用于创建一个高速写入的缓存路径。
示例如下:
docker run -d -p 8802:80 --mount type=tmpfs,destination=/app --name nginx-volume4 nginx:latest
使用docker inspect
命令查看其挂载信息:
docker inspect nginx-volume4 | grep -A 11 "Mounts"
输出结果:
"Mounts": [
{
"Type": "tmpfs",
"Target": "/app"
}
],
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
...
],
"Mounts": [
{
"Type": "tmpfs",
"Source": "",
"Destination": "/app",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
通过查询挂载信息可以发现,tmpfs类型没有在宿主机上指定路径,是因为我们指定到了内存当中。
三种类型挂载的位置
三种类型其本质是,挂载的宿主机文件系统的位置不同。
四、-v与--mount参数的区别
-v
只能挂载2种形式:bind,volume--mount
可以挂载3种形式:bind,volume,tmpfs
两者在功能上是等效的,但--mount
更为灵活,适用于更复杂的挂载需求。使用哪种方式主要取决于具体的使用场景。如果你只需要简单的将主机上的目录挂载到容器内,-v
参数足够简便;如果需要更多挂载选项,推荐使用--mount
参数。
五、docker -v的四种用法
1. 不使用-v参数
示例:
docker run -d -p 8803:80 --name nginx-volume5 nginx:latest
docker inspect nginx-volume5 | grep "Mounts"
输出结果:
"Mounts": [],
当不使用-v
参数时,容器也不会在宿主机上创建volume,此时当容器删除,数据也会跟随删除。
2. -v <容器内路径>
示例:
docker run -d -p 8804:80 -v /usr/share/nginx/html --name nginx-volume6 nginx:latest
docker inspect nginx-volume6 | grep -A 15 "Mounts"
输出结果:
"Mounts": [
{
"Type": "volume",
"Name": "61e5198338d2fffafafe9f1bad51c67c2570506d63124c62355bc4e0e6bea5ef",
"Source": "/var/lib/docker/volumes/61e5198338d2fffafafe9f1bad51c67c2570506d63124c62355bc4e0e6bea5ef/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
当-v
参数仅指定容器内的路径时,将创建一个匿名类型的volume,用于存储容器的数据。
3. -v <Volume 名称>:/<容器内路径>
示例:
docker run -d -p 8805:80 -v NginxVolume7_VolumeName:/usr/share/nginx/html --name nginx-volume7 nginx:latest
docker inspect nginx-volume7 | grep -A 15 "Mounts"
输出结果:
"Mounts": [
{
"Type": "volume",
"Name": "NginxVolume7_VolumeName",
"Source": "/var/lib/docker/volumes/NginxVolume7_VolumeName/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
当-v
参数指定一个不存在的volume时,在创建容器时,docker会自动创建该volume。这两种类型的-v
指定挂载方式,不会存在空挂载现象。
4. -v <宿主机路径>:<容器内路径>
示例:
docker run -d -p 8806:80 -v /home/lemon/nginx_volume8_dir:/usr/share/nginx/html --name nginx-volume8 nginx:latest
docker inspect nginx-volume8 | grep -A 15 "Mounts"
输出结果:
"Mounts": [
{
"Type": "bind",
"Source": "/home/lemon/nginx_volume8_dir",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
当-v
参数将宿主机的目录和容器内的目录关联起来时,默认会用宿主机的目录替换容器内部的目录数据,使用该种方式,需要注意空挂载现象。