docker volume 详解
卷是持久化由Docker容器生成和使用的数据的首选机制。虽然绑定挂载依赖于主机的目录结构,但卷完全由Docker管理。与绑定挂载相比,卷有几个优点:
- 与绑定挂载相比,卷更容易备份或迁移。
- 您可以使用Docker CLI命令或Docker API来管理卷。
- 卷在Linux和Windows容器上都可以工作。
- 卷可以在多个容器之间更安全地共享。
- 卷驱动程序允许您在远程主机或云提供程序上存储卷,加密卷的内容或添加其他功能。
- 新卷的内容可以由容器预先填充。
另外,与使容器的可写层保存数据相比,容量通常是一个更好的选择,因为使用容量不会增加使用容器的容器的大小,而容器的内容存在于给定容器的生命周期之外。
如果您的容器生成非持久状态数据,请考虑使用tmpfs挂载以避免将数据永久存储在任何地方,并通过避免写入容器的可写层来提高容器的性能。
卷使用rprivate绑定传播,并且绑定传播对于卷来说是不可配置的。
选择 -v or –mount 标志
最初,-v或--volume标志用于独立容器,而--mount标志用于群集服务。但是,从Docker 17.06开始,您也可以使用--mount独立的容器。一般来说,--mount更明确和详细。最大的区别在于-v语法将所有选项组合在一个字段中,而--mount语法将它们分开。以下是每个标志的语法比较。
提示:新用户应该使用--mount语法。有经验的用户可能更熟悉-v或--volume语法,但是鼓励使用--mount,因为研究表明它更易于使用。
如果您需要指定卷驱动程序选项,则必须使用--mount。
-
- v或- volume:由三个字段组成,由冒号分隔(:)。字段必须按照正确的顺序书写,并且每个字段的含义都不是立刻确定。
- 在命名卷的情况下,第一个字段是卷的名称,在给定的主机上是惟一的。对于匿名卷,省略了第一个字段。
- 第二个字段是在容器中安装文件或目录的路径。
- 第三个字段是可选的,并且是一个逗号分隔的选项列表,如ro。下面讨论这些选项。
-
--mount:由多个键-值对组成,由逗号分隔,每一对由< key>= <value> tuple(元组)组成。--mount 语法比- v或—volume 更详细,其中键对的顺序并不重要,而且标记的值更容易理解。
- 挂载的类型(type),可以是绑定(bind)、卷(volume)或tmpfs。本主题讨论卷,因此类型将始终是卷。
- 挂载源(source)。对于命名卷,是卷的名称。对于匿名卷,该字段被省略。可以指定为source 或src。
- 挂在目标(destination)的值是将文件或目录安装在容器中的路径。可以指定为destination、dst或target。
- 如果存在readonly选项,则将绑定挂载安装到容器中作为只读。
- 可以使用键值对多次指定的volume-opt选项.
- v和- mount行为之间的差异
与绑定挂载相反,所有的卷的选项对于 --mount 和 -v 标志 都可以使用。
当卷(volume)作为服务时,只支持--mount。
创建和管理卷
与绑定挂载(bind mount)不同,您可以在任何容器范围之外创建和管理卷。
创建卷
$ docker volume create my-vol
查看卷
$ docker volume ls
local my-vol
卷详情
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
删除卷
$ docker volume rm my-vol
容器中使用创建的卷
如果您启动一个带了不存在的卷的容器,Docker将为您创建卷。下面的示例将卷myvol2装入容器 /app 中。
--mount
$ docker run -d \
-it \
--name devtest \
--mount source=myvol2,target=/app \
nginx:latest
-v
$ docker run -d \
-it \
--name devtest \
-v myvol2:/app \
nginx:latest
使用docker inspect devtest来验证卷的创建和挂载是否正确。查找 mount 部分:
"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
这表明挂载是一个卷,它显示了正确的源和目的地,并且挂载是读写的。
停止容器并删除卷。
$ docker container stop devtest
$ docker container rm devtest
$ docker volume rm myvol2
服务中使用卷
当您启动一个服务并定义一个卷时,每个服务容器将使用它自己的本地卷。如果您使用本地卷驱动程序,则没有一个容器可以共享这些数据,但是一些卷驱动程序确实支持共享存储。AWS的Docker和Azure的Docker都支持使用Cloudstor插件的持久性存储。
下面的示例启动一个带有四个副本的nginx服务,每个副本使用一个名为myvol2的本地卷。
$ docker service create -d \
--replicas=4 \
--name devtest-service \
--mount source=myvol2,target=/app \
nginx:lates
使用docker service ps devtest来验证服务是否正在运行:
$ docker service ps devtest-service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
4d7oz1j85wwn devtest-service.1 nginx:latest moby Running Running 14 seconds ago
删除服务,停止该服务所有任务:
$ docker service rm devtest-service
服务的语法差异
docker服务创建命令不支持 - v或 --volume 语法。当将卷安装到服务的容器时,必须使用 --mount 语法
将容器原本的内容放到卷中
如果您启动一个容器,该容器创建一个新卷,如上所述,容器中包含的文件与目录正好与要挂载的卷中的目录一致(例如上面例子中的/app /),容器中的目录中的内容将被复制到卷中。然后容器将装入并使用卷,而使用此卷的其他容器也可以访问这些被copy的内容。
为了说明这一点,这个示例启动一个nginx容器,并将新卷nginx - vol填充到容器/ usr/share/nginx/html目录的内容中,这是nginx存储其默认HTML内容的地方。
The --mount and -v examples have the same end result.
$ docker run -d \
-it \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
nginx:latest
$ docker run -d \
-it \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html \
nginx:latest
在运行这些示例之后,运行以下命令来清理容器和卷。
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
只读卷
对于一些开发中的应用,将数据写入卷中,并体现到宿主机上是非常有用的。另一方面,对于另一些应用,只允许读取卷中的内容则更加合适。毕竟一个卷可以被多个容器挂在,其中一些是读写方式,另一些是只读方式。
例子,注意mount option 使用逗号隔开
$ docker run -d \
-it \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
nginx:latest
$ docker run -d \
-it \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html:ro \
nginx:latest
查看挂载是否正确
docker inspect nginxtest
"Mounts": [
{
"Type": "volume",
"Name": "nginx-vol",
"Source": "/var/lib/docker/volumes/nginx-vol/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": false,
"Propagation": ""
}
],
删除容器和卷
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
使用volume driver
当您使用 docker volume create 创建卷,或者当您创建一个容器,并与一个尚未创建的卷关联时,您可以使用volume driver
Initial set-up
这个例子假设您有两个节点,第一个节点是Docker主机,可以使用SSH连接到第二个节点。
在Docker主机上安装vieux/sshfs插件:
$ docker plugin install --grant-all-permissions vieux/sshfs
创建带volume driver 的卷
示例指定了SSH密码,但如果两个主机配置了免密码登陆(公钥免密),则可以忽略密码。每个卷驱动程序可能有零个或多个可配置选项,每个选项都使用- o标志指定。
$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
sshvolume
创建容器时使用volume driver
如果卷驱动程序要求您传递选项,您必须使用- mount标志来挂载该卷,而不是- v。
$ docker run -d \
-it \
--name sshfs-container \
--volume-driver vieux/sshfs \
--mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
nginx:latest