参考教程:https://docs.docker.com/storage/volumes/
以下内容来自官方文档翻译
环境
- virtual box 6.1
- centos 7.8
- docker 19.03
使用数据卷
Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. While bind mounts are dependent on the directory structure and OS of the host machine, volumes are completely managed by Docker. Volumes have several advantages over bind mounts:
数据卷是持久化 Docker 容器生成和使用的数据的首选机制。因为绑定挂载依赖于主机的目录结构和操作系统,数据卷完全由 Docker 管理。和绑定挂载相比,数据卷具有几个优点:
- Volumes are easier to back up or migrate than bind mounts.
- You can manage volumes using Docker CLI commands or the Docker API.
- Volumes work on both Linux and Windows containers.
- Volumes can be more safely shared among multiple containers.
- Volume drivers let you store volumes on remote hosts or cloud providers, to encrypt the contents of volumes, or to add other functionality.
- New volumes can have their content pre-populated by a container.
- Volumes on Docker Desktop have much higher performance than bind mounts from Mac and Windows hosts.
- 数据卷比绑定挂载更容易备份或迁移。
- 您可以使用 Docker CLI 命令或 Docker API 管理数据卷。
- 数据卷同时在 Linux 和 Windows 容器上工作。
- 数据卷可以在多个容器之间更安全地共享。
- 数据卷驱动程序允许您将卷存储在远程主机或云提供商,以提供数据卷内容的加密或者其它功能。
- 新数据卷的内容可以由容器预先填充。
- 与来自 Mac 和 Windows 主机的绑定挂载相比,Docker Desktop 上的数据卷具有更高的性能。
In addition, volumes are often a better choice than persisting data in a container’s writable layer, because a volume does not increase the size of the containers using it, and the volume’s contents exist outside the lifecycle of a given container.
此外,数据卷通常比在容器的可写层中保存数据更好,因为卷不会增加使用它的容器的大小,并且卷的内容存在于给定容器的生命周期之外。
If your container generates non-persistent state data, consider using a tmpfs mount to avoid storing the data anywhere permanently, and to increase the container’s performance by avoiding writing into the container’s writable layer.
如果容器生成非持久性状态数据,请考虑使用 tmpfs 挂载以避免将数据永久存储在任何地方,并避免写入容器的可写层来提高容器的性能。
-v 和 -mount 的选择
In general, --mount
is more explicit and verbose. The biggest difference is that the -v
syntax combines all the options together in one field, while the --mount
syntax separates them. Here is a comparison of the syntax for each flag.
一般来说,--mount
更明确和冗长。最大的区别在于, -v
语法将所有选项合并到一个字段中,而 --mount
语法将它们分开。下面是每个标志的语法的比较。
If you need to specify volume driver options, you must use --mount
.
如果需要指定数据卷驱动程序选项,则必须使用 --mount
。
-
-v
or--volume
: Consists of three fields, separated by colon characters (:
). The fields must be in the correct order, and the meaning of each field is not immediately obvious.- In the case of named volumes, the first field is the name of the volume, and is unique on a given host machine. For anonymous volumes, the first field is omitted.
- The second field is the path where the file or directory are mounted in the container.
- The third field is optional, and is a comma-separated list of options, such as
ro
. These options are discussed below.
-
-v
或者--volume
:由三个字段组成,用冒号(:
)分隔。字段必须按正确的顺序排列,并且每个字段的含义不是显而易见。- 在命名卷的情况下,第一个字段是卷的名称,在给定的主机上是唯一的。对于匿名卷,省略第一个字段。
- 第二个字段是将文件或目录挂载到容器中的路径。
- 第三个字段是可选的,并且是逗号分隔的选项列表,例如
ro
。下面将讨论这些选项。
-
--mount
: Consists of multiple key-value pairs, separated by commas and each consisting of a<key>=<value>
tuple. The--mount
syntax is more verbose than-v
or--volume
, but the order of the keys is not significant, and the value of the flag is easier to understand. -
--mount
:由多个键值对组成,用逗号分隔,每个键值对由<key>=<value>
元组组成。--mount
语法比-v
和--volume
更详细,键的顺序不重要,并且标志的值更容易理解。-
The
type
of the mount, which can bebind
,volume
, ortmpfs
. This topic discusses volumes, so the type is alwaysvolume
. -
The
source
of the mount. For named volumes, this is the name of the volume. For anonymous volumes, this field is omitted. May be specified assource
orsrc
. -
The
destination
takes as its value the path where the file or directory is mounted in the container. May be specified asdestination
,dst
, ortarget
. -
The
readonly
option, if present, causes the bind mount to be mounted into the container as read-only. -
The
volume-opt
option, which can be specified more than once, takes a key-value pair consisting of the option name and its value. -
挂载的类型,可以是
bind
,volume
或者tmpfs
。本主题讨论数据卷,因此类型始终为volume
。 -
挂载的来源。对于命名卷,这是数据卷的名称。对于匿名卷,省略此字段。可以指定为
source
或者src
-
挂载的目的地是文件或目录挂载在容器中的路径。可以指定为
destination
,dst
或者target
。 -
如果
readonly
存在,该选项只会挂载一个只读的数据卷。 -
volume-opt
可以指定多次,采用键值对的形式。
-
数据卷的操作
数据卷的所有命令
[root@master ~]# docker volume
Usage: docker volume COMMAND
Manage volumes
Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove all unused local volumes
rm Remove one or more volumes
Run 'docker volume COMMAND --help' for more information on a command.
列出数据卷
[root@master ~]# docker volume ls --help
Usage: docker volume ls [OPTIONS]
List volumes
Aliases:
ls, list
Options:
-f, --filter filter Provide filter values (e.g. 'dangling=true')
--format string Pretty-print volumes using a Go template
-q, --quiet Only display volume names
[root@master ~]# docker volume ls
DRIVER VOLUME NAME
local eab77839cbab7a3123c8151031dcd2fcc71aff7a8306613502a4866d0ff232a4
local nexus-data
创建数据卷
[root@master ~]# docker volume create --help
Usage: docker volume create [OPTIONS] [VOLUME]
Create a volume
Options:
-d, --driver string Specify volume driver name (default "local")
--label list Set metadata for a volume
-o, --opt map Set driver specific options (default map[])
[root@master ~]# docker volume create my-vol
my-vol
查看数据卷
[root@master ~]# docker volume inspect --help
Usage: docker volume inspect [OPTIONS] VOLUME [VOLUME...]
Display detailed information on one or more volumes
Options:
-f, --format string Format the output using the given Go template
[root@master ~]# docker volume inspect my-vol
[
{
"CreatedAt": "2020-10-31T06:38:43+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
[root@master ~]#
删除数据卷
[root@master ~]# docker volume rm --help
Usage: docker volume rm [OPTIONS] VOLUME [VOLUME...]
Remove one or more volumes. You cannot remove a volume that is in use by a container.
Aliases:
rm, remove
Examples:
$ docker volume rm hello
hello
Options:
-f, --force Force the removal of one or more volumes
[root@master ~]# docker volume remove my-vol
my-vol
使用未命名数据卷
[root@master ~]# docker run -p8080:80 --mount dst=/usr/share/nginx/html -d nginx
91f5469eeeb4ffe12c385edcab40fba3b0865d366aa33b5f49010ab6cfc84cab
[root@master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
91f5469eeeb4 nginx "/docker-entrypoint.…" 9 seconds ago Up 7 seconds 0.0.0.0:8080->80/tcp wonderful_booth
[root@master ~]# docker volume ls
DRIVER VOLUME NAME
local 0d34810d835e236577f6f101f0b1ebf0174973ae4a38b9d938ecf6f269a49362
local eab77839cbab7a3123c8151031dcd2fcc71aff7a8306613502a4866d0ff232a4
local nexus-data
[root@master ~]# docker container inspect 91 --format '{{json .Mounts}}' | jq
[
{
"Type": "volume",
"Name": "0d34810d835e236577f6f101f0b1ebf0174973ae4a38b9d938ecf6f269a49362",
"Source": "/var/lib/docker/volumes/0d34810d835e236577f6f101f0b1ebf0174973ae4a38b9d938ecf6f269a49362/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
]
使用命名数据卷
[root@master ~]# docker run -P --mount src=nginx-volume,dst=/usr/share/nginx/html -d nginx
b3d9ca1cf5c1853961e004d451a289f4641d8a4af15796f85034298d3ac11ead
[root@master ~]# docker port b3d
80/tcp -> 0.0.0.0:32768
[root@master ~]#
[root@master ~]# docker volume ls
DRIVER VOLUME NAME
local 0d34810d835e236577f6f101f0b1ebf0174973ae4a38b9d938ecf6f269a49362
local eab77839cbab7a3123c8151031dcd2fcc71aff7a8306613502a4866d0ff232a4
local nexus-data
local nginx-volume
[root@master ~]# docker container inspect b3d --format '{{json .Mounts}}' | jq
[
{
"Type": "volume",
"Name": "nginx-volume",
"Source": "/var/lib/docker/volumes/nginx-volume/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
]
查看数据卷详情
[root@master ~]# docker volume inspect nginx-volume
[
{
"CreatedAt": "2020-10-31T07:12:26+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginx-volume/_data",
"Name": "nginx-volume",
"Options": null,
"Scope": "local"
}
]
只读数据卷
[root@master ~]# docker run -P --mount src=nginx-volume,dst=/usr/share/nginx/html,readonly -d nginx
7b5d9210f71f1ed7dc733b7f3151351ea41cb54b86d04f8b173fbd5f4406db7f
[root@master ~]# docker container inspect 7b5 --format '{{json .Mounts}}' | jq
[
{
"Type": "volume",
"Name": "nginx-volume",
"Source": "/var/lib/docker/volumes/nginx-volume/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": false,
"Propagation": ""
}
]
数据卷共享数据
[root@master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7b5d9210f71f nginx "/docker-entrypoint.…" 4 minutes ago Up 4 minutes 0.0.0.0:32769->80/tcp pedantic_hugle
b3d9ca1cf5c1 nginx "/docker-entrypoint.…" 9 minutes ago Up 9 minutes 0.0.0.0:32768->80/tcp boring_benz
[root@master ~]# docker exec -it b3d bash
root@b3d9ca1cf5c1:/# cd usr/share/nginx/html/
root@b3d9ca1cf5c1:/usr/share/nginx/html# ls
50x.html index.html
root@b3d9ca1cf5c1:/usr/share/nginx/html# echo 'hello world' > index.html
root@b3d9ca1cf5c1:/usr/share/nginx/html# exit
exit
[root@master ~]# curl localhost:32769
hello world
[root@master ~]# docker volume inspect nginx-volume
[
{
"CreatedAt": "2020-10-31T07:12:26+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/nginx-volume/_data",
"Name": "nginx-volume",
"Options": null,
"Scope": "local"
}
]
[root@master ~]# cat /var/lib/docker/volumes/nginx-volume/_data/index.html
hello world
数据卷的备份和恢复
生成数据卷
[root@master ~]# docker run -P -d --mount type=volume,src=nginx-volume,dst=/usr/share/nginx/html nginx:alpine
6264f7e1c20b4799845ef809fb7e065febccb25e0b75d7cfc2c32b78b76a8980
[root@master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6264f7e1c20b docker.io/library/nginx:alpine nginx -g daemon o... 22 seconds ago Up 5 seconds ago 0.0.0.0:44425->80/tcp objective_johnson
修改挂载内容
[root@master ~]# docker exec -it 626 /bin/sh
/ # ls
bin etc mnt run tmp
dev home opt sbin usr
docker-entrypoint.d lib proc srv var
docker-entrypoint.sh media root sys
/ # ll
/bin/sh: ll: not found
/ # cd usr/share/nginx/html/
/usr/share/nginx/html # ll
/bin/sh: ll: not found
/usr/share/nginx/html # ls
50x.html index.html
/usr/share/nginx/html # echo "hello world!" > index.html
/usr/share/nginx/html # exit
[root@master ~]# curl localhost:44425
hello world!
查看数据卷位置
[root@master ~]# docker volume ls
dockeDRIVER VOLUME NAME
local nginx-volume
[root@master ~]# docker volume inspect nginx-volume
[
{
"Name": "nginx-volume",
"Driver": "local",
"Mountpoint": "/var/lib/containers/storage/volumes/nginx-volume/_data",
"CreatedAt": "2020-11-02T12:11:26.383688716+08:00",
"Labels": {
},
"Scope": "local",
"Options": {
}
}
]
[root@master ~]# cd /var/lib/containers/storage/volumes/
备份数据卷
[root@master volumes]# tar -zcvf nginx-volume.tar.gz nginx-volume
nginx-volume/
nginx-volume/_data/
nginx-volume/_data/50x.html
nginx-volume/_data/index.html
[root@master volumes]# mv nginx-volume.tar.gz ~
删除数据卷
[root@master volumes]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6264f7e1c20b docker.io/library/nginx:alpine nginx -g daemon o... 3 minutes ago Up 3 minutes ago 0.0.0.0:44425->80/tcp objective_johnson
[root@master volumes]# docker stop 626
6264f7e1c20b4799845ef809fb7e065febccb25e0b75d7cfc2c32b78b76a8980
[root@master volumes]# docker container prune
6264f7e1c20b4799845ef809fb7e065febccb25e0b75d7cfc2c32b78b76a8980
[root@master volumes]# docker volume ls
DRIVER VOLUME NAME
local nginx-volume
[root@master volumes]# docker volume rm nginx-volume
nginx-volume
启动新容器
[root@master volumes]# docker run -P -d --name web --mount type=volume,src=nginx-volume,dst=/usr/share/nginx/html nginx:alpine
8f5b867e5f937c84729f09031a1d44e1d1e36599ee25262775113a2e9da3c4b5
[root@master volumes]# ls
nginx-volume
[root@master volumes]# tar -zxvf ~/nginx-volume.tar.gz
nginx-volume/
nginx-volume/_data/
nginx-volume/_data/50x.html
nginx-volume/_data/index.html
[root@master volumes]# ll
total 0
drwx------. 3 root root 19 Nov 2 12:11 nginx-volume
验证还原效果
[root@master volumes]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8f5b867e5f93 docker.io/library/nginx:alpine nginx -g daemon o... About a minute ago Up About a minute ago 0.0.0.0:36962->80/tcp web
[root@master volumes]# curl localhost:36962
hello world!
查看数据卷挂载变化
数据卷的实现方式是使用 Linux 的挂载实现的。同时,在使用 commit 创建镜像时,数据卷的内容也不会被提交。
[root@master _data]# docker container diff ed
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
A /var/cache/nginx/uwsgi_temp
C /run
A /run/nginx.pid
C /etc
C /etc/nginx
C /etc/nginx/conf.d
C /etc/nginx/conf.d/default.conf
总结
介绍了数据卷的基础使用,包括增加删除等,使用数据卷存储和共享数据,以及备份和恢复。