环境:centos7.9 docker version 20.10.14
本篇我们来介绍docker的数据卷,数据卷是用于实现docker数据的持久化。
使用docker过程中,我们需要持久化容器中产生的数据,以及容器与容器之间、容器与主机之前进行数据共享、备份等操作,这里就需要到容器的数据持久化管理。 docker的数据持久化管理目前提供如下两种方式:
1、数据卷 data volumes
2、数据卷容器 data volumes containers
数据卷:数据卷其实就是一个目录或文件,类似linux下对目录或文件进行mount挂载操作,即在宿主机和容器之间建立一个或多个目录(文件亦可)来相互映射文件,其具有如下特点:
(1) 数据卷可以在容器之间进行共享和重用,即多个容器可以挂载同一个目录
(2)对数据卷的更改会立即生效,即对宿主机目录下的文件的修改会立即反应到容器的挂载点目录文件
(3)对数据卷的更新不会影响到镜像 (镜像只读)
(4)卷会一直存在,即使容器被删除,即宿主机目录不会因为容器的删除而删除宿主机目录
注意:
(1)删除容器的时候,数据卷不会删除。如果要删除容器的时候同时删除数据卷,需加上-v参数。比如: docker rm os456 -v /homedata
(2)默认数据卷挂载以后文件的权限为rw
,如需单独设置,可以容器数据卷后边设置:ro只读
。
docker run -v
参数语法:
-v是--volume的缩写,表示绑定挂载卷,语法格式:
-v <host_path>:<container_path>[:rw/ro]
<host_path>是宿主机的目录或单个文件
<container_path>是容器的目录或单个文件
rw/ro 表示挂载后容器的数据读写权限,rw表示读写,ro表示数据只读,不写默认就是rw读写权限
演示示例:
#使用数据卷挂载宿主机目录到容器中去
mkdir /root/nginx/html -p
docker run -d --name nginx -p 8081:80 -v /root/nginx/html:/usr/share/nginx/html nginx:latest
#使用数据卷挂载但个文件到容器中去
docker run -d --name nginx -p 8081:80 -v /root/nginx/html/index.html:/usr/share/nginx/html/index.html nginx:latest
#综合案例
mkdir -p /root/nginx/html && echo "good" >> /root/nginx/html/index.html
mkdir -p /root/nginx/logs -p
docker run -d --name nginx2 -p 8081:80 -v /root/nginx/html/index.html:/usr/share/nginx/html/index.html nginx:latest
docker inspect nginx
"Mounts": [
{
"Type": "bind", #可以看到类型是bind,所以没有产生volume
"Source": "/root/nginx/html",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
使用-v
参数时可以不指定
部分,只需指定容器的挂载点即可,如:-v
,container_path必须是一个容器目录,不能是单个文件了,数据权限不能设置,均为读写权限。这时docker会自动创建一个匿名的数据卷,这个匿名数据卷的名字是自动生成的一个很长串的字符。使用docker volume ls
命令可以看到这个数据卷的名称,我们称这种卷为匿名数据卷。
演示示例:
使用-v挂载匿名卷,docker会默认给我们在宿主机上找一个目录进行挂载
docker run -d --name nginx2 -p 8081:80 -v /usr/share/nginx/html -v /var/log/nginx nginx:latest
#查看容器的详细信息就可以发现docker将我们的卷挂载到哪里了
[root@docker ~]# docker inspect nginx2
"Mounts": [
{
"Type": "volume", #类型是volume
"Name": "8d1d766c65d3b3cddafd20f25d",
"Source": "/var/lib/docker/volumes/8d1d766c65d3b3cddafd20f25d/_data",
#上面一行,可见,docker将卷挂到了这里,这个很长串的ID其实就是数据卷的名称
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume", #类型是volume
"Name": "ef17aa81669f4ef7704182061164bce",
"Source": "/var/lib/docker/volumes/ef17aa81669f4ef7704182061164bce/_data",
"Destination": "/var/log/nginx",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
[root@docker ~]# ls -l /var/lib/docker/volumes/8d1d766c65d3b3cddafd20f25d/_data/
total 8
-rw-r--r--. 1 root root 497 Dec 28 2021 50x.html
-rw-r--r--. 1 root root 615 Dec 28 2021 index.html
# 所以我们修改/var/lib/docker/volumes/8d1d766c65d3b3cddafd20f25d/_data/下的index.html文件就能实现容器的nginx页面的变更
不同点 | bind mount | docker manager volume |
---|---|---|
volume位置 | 可挂载宿主机任意位置的目录或文件 | 仅挂载宿主机固定位置的目录,目录一般为/var/lib/docker/volumes/xxx/_data/ |
对容器挂载点影响 | 挂载后容器内的挂载点目录会被覆盖,如果此时宿主机目录上没有文件,那么容器的挂载点也没有文件 | 使用匿名数据卷时,如果volume是空的而container中的目录有内容,那么docker会将container目录中的内容拷贝到volume中,但是如果volume中已经有内容,则会将container中的目录覆盖 |
是否支持单文件 | 支持挂载目录或单文件 | 仅支持挂载目录 |
权限控制 | 权限默认rw,可设置为ro | 只能默认rw |
移植性 | 移植性弱,与宿主机路径绑定 | 移植性强,无需指定宿主机目录 |
匿名数据卷 docker manager volume
使用-v参数时不指定
部分,只需指定容器的挂载点即可,如:-v
,这是docker默认会创建目录,如/var/lib/docker/volumes/8d1d766c65d3b3cddafd20f25dcaf304a96b9c89d005d30226a7b815a6b5ecbf/_data/
目录,这个目录就是容器持久化数据的目录,这一串很长的ID就是卷名,docker自动帮我们生成的,通过docker volume ls命令可以查看卷。
注意:
使用数据卷 bind mount ,即-v参数
,挂载后容器内的挂载点目录会被覆盖,如果此时宿主机目录上没有文件,那么容器的挂载点也没有文件;
使用匿名数据卷时,如果volume是空的而container中的目录有内容,那么docker会将container目录中的内容拷贝到volume中,但是如果volume中已经有内容,则会将container中的目录覆盖。
[root@docker ~]# docker volume --help
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
#列出全部的volume
docker volume ls
#查看指定名字的volume的详细信息
docker volume inspect a0dc63aae530f4070bb34e1c5331319c93a97f3727e6cf60415b7847010dcaf8
#移除全部未使用的本地volume
docker volume prune
#删除指定的volume
docker volume rm a0dc63aae530f4070bb34e1c5331319c93a97f3727e6cf60415b7847010dcaf8
示例:
#创建一个数据卷,名称叫做nginx
[root@docker ~]# docker volume create nginx
nginx
[root@docker ~]# docker volume ls | grep nginx
local nginx
[root@docker ~]# docker volume inspect nginx
[
{
"CreatedAt": "2023-08-27T14:40:43+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/nginx/_data",
"Name": "nginx",
"Options": {},
"Scope": "local"
}
]
#容器使用数据卷,-v参数时加上卷名即可
[root@docker ~]# docker run -d --name nginx -p 8081:80 -v nginx:/usr/share/nginx/html nginx:latest
57022b423ec03bdb1a7a178544d422b262daa1b2861ba8a509a20962ed3051cf
[root@docker ~]# docker inspect nginx
"Mounts": [
{
"Type": "volume",
"Name": "nginx",
"Source": "/var/lib/docker/volumes/nginx/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
#可以看到,nginx已经使用了nginx数据卷
#注意
#使用数据卷 bind mount ,-v参数,不会产生volume,如下:
docker run -d --name nginx -p 8081:80 -v /root/nginx/html:/usr/share/nginx/html nginx:latest
docker inspect nginx
"Mounts": [
{
"Type": "bind", #可以看到类型是bind,所以没有产生volume
"Source": "/root/nginx/html",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
所谓数据卷容器,其实就是一个为其他容器提供volume的容器,即包含数据的容器,然后其他多个容器可以通过--volumes-from 数据卷容器名
参数来挂载数据卷容器,从而实现多个容器共享同一份数据。
1、不使用数据卷容器之前,多个容器共享相同的数据,只需使用-v参数挂载同一个宿主机目录即可,如下实现:
docker run -d --name nginx1 -p 8081:80 -v /root/nginx/html/:/usr/share/nginx/html nginx:latest
docker run -d --name nginx2 -p 8082:80 -v /root/nginx/html/:/usr/share/nginx/html nginx:latest
docker run -d --name nginx3 -p 8083:80 -v /root/nginx/html/:/usr/share/nginx/html nginx:latest
echo "good" >>/root/nginx/html/index.html
curl 127.0.0.1:8081
good
curl 127.0.0.1:8082
good
curl 127.0.0.1:8083
good
#以上使用的是bind mount的形式挂载,当然也可以手动创建一个volume,如下:
docker volume create nginx
docker volume inspect nginx
[
{
"CreatedAt": "2023-08-27T14:40:43+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/nginx/_data",
"Name": "nginx",
"Options": {},
"Scope": "local"
}
]
echo "good" >>/var/lib/docker/volumes/nginx/_data/index.html
docker run -d --name nginx11 -p 8001:80 -v nginx:/usr/share/nginx/html nginx:latest
docker run -d --name nginx12 -p 8002:80 -v nginx:/usr/share/nginx/html nginx:latest
docker run -d --name nginx13 -p 8003:80 -v nginx:/usr/share/nginx/html nginx:latest
curl 127.0.0.1:8001
I am good
curl 127.0.0.1:8002
I am good
curl 127.0.0.1:8003
I am good
#以上就说明多个容器共享了相同的数据
#注意:不能使用匿名卷,匿名卷会自动创建volume,那么多个容器都各自创建自己的匿名卷这样做不到数据共享了
2、使用数据卷容器之后,多个容器共享相同的数据,如下实现:
#创建一个数据卷容器,名称叫做nginx-data,数据卷容器可以不用run,其只是提供数据而已
echo "I am good man" >/root/nginx/html/index.html
docker create --name nginx-data -v /root/nginx/html/:/usr/share/nginx/html nginx:latest
#使用volume亦可,docker create --name nginx-data -v nginx:/usr/share/nginx/html nginx:latest
#其他nginx容器共享数据卷容器数据
#nginx容器的挂载和数据卷容器的挂载是一样的
docker run -d --name nginx1 -p 8001:80 --volumes-from nginx-data nginx:latest
docker run -d --name nginx2 -p 8002:80 --volumes-from nginx-data nginx:latest
docker run -d --name nginx3 -p 8003:80 --volumes-from nginx-data nginx:latest
curl 127.0.0.1:8001
I am good man
curl 127.0.0.1:8002
I am good man
curl 127.0.0.1:8003
I am good man
#删除数据卷容器
docker rm nginx-data
# nginx3 容器依然可以访问
curl 127.0.0.1:8003
I am good man
#查看nginx3 的挂载目录
"Mounts": [
{
"Type": "bind", #bind类型,因为nginx-data数据卷容器就是使用bind类型
"Source": "/root/nginx/html", #宿主机目录
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
#我们可以看到,即使数据卷容器被删除了,使用数据卷容器的其他nginx容器依然能正常持久化数据
#这说明,其他nginx容器其实本质上还是挂载宿主机上的目录,这其实和多个容器使用相同的-v /root/nginx/html/:/usr/share/nginx/html 没说
#明区别
#以上只演示了使用bind mount 类型的卷,其实手动创建一个数据卷docker volume create nginx-data,然后,多个容器都使用该nginx-data数据
# 卷亦可以共享数据,或者数据卷容器挂载的是nginx-data数据卷,然后多个容器都使用该nginx-data数据卷也是可以的.
所谓孤儿volume是指没有被任何容器使用的volume。
删除volume:
1、对于直接使用-v /root/nginx/html/:/usr/share/nginx/html
指定宿主机目录挂载的,当删除容器时,宿主机上的目录并不会被删除,这也是数据持久化的含义,所以如果需要永久删除宿主机目录,可以在确认数据不再需要后删除宿主机目录即可。
2、对于使用docker manager volume管理的,如果是匿名卷,在删除容器的时候加上-v可以直接删除容器和匿名卷,docker rm命令如下:
[root@docker ~]# docker rm --help
Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
Remove one or more containers
Options:
-f, --force Force the removal of a running container (uses SIGKILL)
-l, --link Remove the specified link
-v, --volumes Remove anonymous volumes associated with the container #-v参数删除分配给容器的匿名卷
#删除容器的同时删除容器的匿名卷
docker rm nginx1 -v -f
3、对于不管是匿名卷还是有名卷,都可以使用docker volume rm
命令删除卷。
4、孤儿volume是指没有被任何容器使用的volume。在确定volume不再使用后,可以使用docker volume rm
命令删除卷。
docker run --help | grep mount
--mount mount Attach a filesystem mount to the container
--mount参数其实也是挂载一个目录或卷到容器中,与-v其实是相同的功能。
挂载bind mount命令格式:type=bind,source=/path/on/host,destination=/path/in/container[,...]
挂载volume命令格式:[type=volume,]source=my-volume,destination=/path/in/container[,...]
参数的顺序不重要。
示例1:
mkdir /tmp/test && echo "Test" >>/tmp/test/file1.txt
docker run -itd --mount type=bind,source=/tmp/test,target=/tmp busybox1:v1
docker exec -it 3a70c2c663b46 sh #进入容器,可以正常查看文件,测试在宿主上再创建几个文件,在容器里面也能看到
/data # cat /tmp/file.txt
Test
/data # exit
docker inspect 3a70c2c663b468 | grep -A9 Mounts
"Mounts": [
{
"Type": "bind",
"Source": "/tmp/test",
"Destination": "/tmp",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
示例2:
docker volume create nginx
docker inspect nginx --type volume | grep Mountpoint
"Mountpoint": "/var/lib/docker/volumes/nginx/_data",
echo "AAAAAA" >> /var/lib/docker/volumes/nginx/_data/nginx.log
docker run -itd --mount type=volume,source=nginx,target=/tmp busybox1:v1
docker exec -it dac0565abccce7 cat /tmp/nginx.log
AAAAAA
echo "err" >> /var/lib/docker/volumes/nginx/_data/nginx.err
docker exec -it dac0565abccce7 cat /tmp/nginx.err
err
[root@rancher city]# docker inspect dac0565abccce7 --type container | grep -A9 -i Mounts
"Mounts": [
{
"Type": "volume",
"Name": "nginx",
"Source": "/var/lib/docker/volumes/nginx/_data",
"Destination": "/tmp",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
docker容器实现数据持久化一般有以下几种方式:
1、-v参数,以bind mount方式挂载宿主机目录或文件到容器
docker run -v参数语法:
-v <host_path>:<container_path>[:rw/ro]
<host_path>是宿主机的目录或单个文件
<container_path>是容器的目录或单个文件
rw/ro 表示挂载后容器的数据读写权限,rw表示读写,ro表示数据只读,不写默认就是rw读写权限
示例:
mkdir /root/nginx/html -p
docker run -d --name nginx1 -p 8081:80 -v /root/nginx/html:/usr/share/nginx/html nginx:latest
docker run -d --name nginx2 -p 8082:80 -v /root/nginx/html/index.html:/usr/share/nginx/html/index.html nginx:latest
docker inspect nginx1
"Mounts": [
{
"Type": "bind", #类型是bind
"Source": "/root/nginx/html",
"Destination": "/usr/share/nginx/html",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
2、-v 不指定<host_path>部分时,docker默认使用匿名卷,docker manager volume
使用-v参数时可以不指定<host_path>部分,只需指定容器的挂载点即可,如:-v <container_path>,container_path必须是一个容器目录,不
能是单个文件了,数据权限不能设置,均为读写权限。因为没写<host_path>部分,这时docker会自动创建一个数据卷,这个数据卷的名字是自动生成
的一个很长串的字符,所以叫匿名卷。
docker run -d --name nginx -p 8082:80 -v /usr/share/nginx/html nginx:latest
docker inspect nginx
"Mounts": [
{
"Type": "volume", #类型是volume
"Name": "58b3689c8256a8d33d9114c52b",
"Source": "/var/lib/docker/volumes/58b3689c8256a8d33d9114c52b/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
[root@docker ~]# docker volume list | grep 58b3689c8256a8d33d9114c52b
local 58b3689c8256a8d33d9114c52b
[root@docker ~]#
3、使用创建好的数据卷
#docker volume命令用于管理数据卷
#创建一个数据卷,名称叫做nginx
[root@docker ~]# docker volume create nginx
nginx
[root@docker ~]# docker volume ls | grep nginx
local nginx
[root@docker ~]# docker volume inspect nginx
[
{
"CreatedAt": "2023-08-27T14:40:43+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/nginx/_data",
"Name": "nginx",
"Options": {},
"Scope": "local"
}
]
#创建一个容器并使用名称叫做nginx的volume卷,使用-v参数时指定volume卷名即可
[root@docker ~]# docker run -d --name nginx -p 8081:80 -v nginx:/usr/share/nginx/html nginx:latest
57022b423ec03bdb1a7a178544d422b262daa1b2861ba8a509a20962ed3051cf
[root@docker ~]# docker inspect nginx
"Mounts": [
{
"Type": "volume", #类型是volume
"Name": "nginx", #卷的名称
"Source": "/var/lib/docker/volumes/nginx/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
#列出全部的volume
docker volume ls
#查看指定名字的volume的详细信息
docker volume inspect a0dc63aae530f4070bb34e1c5331319c93a97f3727e6cf60415b7847010dcaf8
#移除全部未使用的本地volume
docker volume prune
#删除指定的volume
docker volume rm a0dc63aae530f4070bb34e1c5331319c93a97f3727e6cf60415b7847010dcaf8
4、数据卷容器
1、不使用数据卷容器之前,多个容器共享相同的数据,只需使用-v参数挂载同一个宿主机目录即可,如下实现:
docker run -d --name nginx1 -p 8081:80 -v /root/nginx/html/:/usr/share/nginx/html nginx:latest
docker run -d --name nginx2 -p 8082:80 -v /root/nginx/html/:/usr/share/nginx/html nginx:latest
docker run -d --name nginx3 -p 8083:80 -v /root/nginx/html/:/usr/share/nginx/html nginx:latest
echo "good" >>/root/nginx/html/index.html
#以上使用的是bind mount的形式挂载,当然也可以手动创建一个volume,如下:
docker volume create nginx
docker volume inspect nginx
[ {
.......
"Mountpoint": "/var/lib/docker/volumes/nginx/_data",
"Name": "nginx",
......
}
]
echo "good" >>/var/lib/docker/volumes/nginx/_data/index.html
docker run -d --name nginx11 -p 8001:80 -v nginx:/usr/share/nginx/html nginx:latest
docker run -d --name nginx12 -p 8002:80 -v nginx:/usr/share/nginx/html nginx:latest
docker run -d --name nginx13 -p 8003:80 -v nginx:/usr/share/nginx/html nginx:latest
#以上就说明多个容器共享了相同的数据
#注意:不能使用匿名卷,匿名卷会自动创建volume,那么多个容器都各自创建自己的匿名卷这样做不到数据共享了
2、使用数据卷容器之后,多个容器共享相同的数据,如下实现:
#创建一个数据卷容器,名称叫做nginx-data,数据卷容器可以不用run,其只是提供数据而已
echo "I am good man" >/root/nginx/html/index.html
docker create --name nginx-data -v /root/nginx/html/:/usr/share/nginx/html nginx:latest
#使用volume亦可,docker create --name nginx-data -v nginx:/usr/share/nginx/html nginx:latest
#其他nginx容器共享数据卷容器数据,使用--volumes-from指定数据卷容器
#nginx容器的挂载和数据卷容器的挂载是一样的
docker run -d --name nginx1 -p 8001:80 --volumes-from nginx-data nginx:latest
docker run -d --name nginx2 -p 8002:80 --volumes-from nginx-data nginx:latest
docker run -d --name nginx3 -p 8003:80 --volumes-from nginx-data nginx:latest
5、孤儿卷
所谓孤儿volume是指没有被任何容器使用的volume。
删除volume:
1、对于直接使用`-v /root/nginx/html/:/usr/share/nginx/html`指定宿主机目录挂载的,当删除容器时,宿主机上的目录并不会被删除,这也是
数据持久化的含义,所以如果需要永久删除宿主机目录,可以在确认数据不再需要后删除宿主机目录即可。
2、对于使用docker manager volume管理的,如果是匿名卷,在删除容器的时候加上-v可以直接删除容器和匿名卷,docker rm命令如下:
[root@docker ~]# docker rm --help
Usage: docker rm [OPTIONS] CONTAINER [CONTAINER...]
Remove one or more containers
Options:
-f, --force Force the removal of a running container (uses SIGKILL)
-l, --link Remove the specified link
-v, --volumes Remove anonymous volumes associated with the container #-v参数删除分配给容器的匿名卷
#删除容器的同时删除容器的匿名卷
docker rm nginx1 -v -f
3、对于不管是匿名卷还是有名卷,都可以使用`docker volume rm` 命令删除卷。
4、docker volume prune #移除全部未使用的本地volume
6、--mount
参数也可挂载目录或卷到容器
docker run --help | grep mount
--mount mount Attach a filesystem mount to the container
--mount参数其实也是挂载一个目录或卷到容器中,与-v其实是相同的功能。
挂载bind mount命令格式:type=bind,source=/path/on/host,destination=/path/in/container[,...]
挂载volume命令格式:[type=volume,]source=my-volume,destination=/path/in/container[,...]
参数的顺序不重要。
示例1:
mkdir /tmp/test && echo "Test" >>/tmp/test/file1.txt
docker run -itd --mount type=bind,source=/tmp/test,target=/tmp busybox1:v1
这样在容器/tmp目录和宿主机/tmp/test目录里面的文件就是相同的,在任一侧创建的文件,另一侧都可以读取。
示例2:
docker volume create nginx
docker inspect nginx --type volume | grep Mountpoint
"Mountpoint": "/var/lib/docker/volumes/nginx/_data",
echo "AAAAAA" >> /var/lib/docker/volumes/nginx/_data/nginx.log
docker run -itd --mount type=volume,source=nginx,target=/tmp busybox1:v1
docker exec -it dac0565abccce7 cat /tmp/nginx.log
AAAAAA
这样在容器/tmp目录和宿主机/var/lib/docker/volumes/nginx/_data目录里面的文件就是相同的,在任一侧创建的文件,另一侧都可以读取。
7、最喜欢使用哪个参数
在实际生产中,一般最常用-v参数直接挂载宿主机目录即可,volume也是很常用的,–mount参数了解即可。