Docker 容器卷

简介

docker镜像下载就是分层的。
最下面是底层的,与Linux的系统内核一致。
再下载的就是往上叠加。
下面的这种情况7就会把5覆盖。
下载镜像会出现already exists 已经存在。

1
2
3
4
        7
4 5 6
1 2 3
0

我们不可以修改镜像,我们启动的容器的最底层就是我们所指定的镜像,我们再修改的时候,是在镜像新建了一层,如果有重复就会覆盖。就像上面7覆盖5一样。

查看容器卷

通过docker inspect id查看容器详细信息
Mounts:就是对应容器挂载。可使用docker inspect id | grep "Mounts" -A 20 来进行快捷查看
Source:Linux
Destination:容器

挂载之后,docker rm -f id删除容器之后,本地的卷依然存在,(–rm 匿名挂载的卷除外,但是 –rm 的具名挂载就会依然存在)。

容器卷命令

1
2
3
4
5
6
7
8
9
10
11
docker volume --help 查看数据卷帮助

create 创建一个卷
inspect 查看一个或多个卷的详情信息
ls 查看卷的列表(不会显示 路径挂载,因为路径挂载 没有卷名)
docker volume ls -q 只显示卷名
prune 移除本地不用的卷(不管是否匿名/具名)
只有 docker ps -a 不显示,才可以移除,需要回答 y 确定。
若不想回答可以使用 docker volume prune -f
rm 删除一个或多个卷(只有 docker ps -a 不显示,才可以移除,加上-f才可以删除具名)
docker volume rm -f $(docker volume ls -q) 个人理解:效果等同于 docker volume prune -f

具名挂载创建

1
2
3
4
[root@localhost ~]# docker volume ls
DRIVER VOLUME NAME
local 389740eca21fa1550398fa833834006b3b06ee2ff9f0b460a499ee3bd4672b6c
local 3fbd7f312df4fe05190ce73532ad2371df7b92fa5a8d2d2bd1ded2c02370635f

具名挂载【-v 卷名:容器路径】
docker run -P --name nginx01 -v juming-nginx:/etc/nginx -d nginx

1
2
3
4
5
[root@localhost ~]# docker volume ls
DRIVER VOLUME NAME
local 389740eca21fa1550398fa833834006b3b06ee2ff9f0b460a499ee3bd4672b6c
local 3fbd7f312df4fe05190ce73532ad2371df7b92fa5a8d2d2bd1ded2c02370635f
local juming-nginx

查看卷的信息

docker volume inspect 卷名查看卷的信息

docker的所有信息默认/var/lib/docker,其中/var/lib/docker/volumes就是放所有卷的。
默认把-v指定的容器路径的东西映射到/var/lib/docker/volumes/xxx/_data

三种挂载方式

1
2
3
4
5
匿名挂载:-v 容器路径

具名挂载:-v 卷名:容器路径

路径挂载:-v Linux路径:容器路径

说明:
1、匿名挂载:如果 Dockerfile 指定了VOLUME PATH1 [PATH2] ...,若 docker run 时不使用 具名挂载,或路径挂载,默认使用匿名挂载,相当于 docker run ... -v PATH1 [-v PATH2] ...
2、路径挂载在使用docker volume ls 不会显示,因为它是 路径挂载,而不会拥有 卷名。
3、匿名挂载会随机分配一下卷名 xxx,匿名挂载/具名挂载对应的路径就是 /var/lib/docker/volumes/卷名/_data
4、在使用--rm与匿名挂载一起使用时,也就是docker run --rm ... -v 容器路径,容器不在了,卷也会不在。只有这一种情况的卷才是非持久化的。
5、匿名挂载,具名挂载都是容器路径下的东西挂载到本地的/var/lib/docker/volumes/卷名/_data,而路径挂载是Linux路径下的内容挂载到容器路径下
6、匿名挂载可以使用docker rm -fv 容器id进行删除容器并移除卷,具名挂载则不可以。因为docker rm -fv只会移除与容器绑定的匿名卷。

拓展:只读

1
2
3
容器路径后面跟:ro 或 :rw
ro readonly 只读(只能从外部改变,容器内部不能修改)
rw readwrite 可读可写(默认)

测试Dockerfile

docker镜像是一层一层的,Dockerfile就是一层一层的,每个命令就是一层

1
2
3
4
5
6
7
FROM nginx

#匿名挂载
VOLUME ["volume01","volume02"]

CMD echo "done..."
CMD /bin/bash

docker build -t taopanfeng/nginx:1.0 .

docker images就可以查看到新生成的镜像了

docker run --name x01 -it taopanfeng/nginx:1.0 /bin/bash
启动之后,就会进入容器

此时我们在容器的/根目录,我们ls -l就可以看到我们的volume01 volume02。
因为默认 WORKDIR 工作目录就是 /根目录,而容器启动时,卷指定的目录不存在,就自动创建目录。

我们exit退出容器,在容器外执行docker inspect 容器id | grep "Mounts" -A 20查看Mounts模块就可以看到volume01 volume02映射的本地路径。
容器卷是在/var/lib/docker/volumes/xxx/_data,其中xxx就是卷名

多容器共享卷

多个容器共享容器卷

docker run --name x02 -it --volumes-from x01 taopanfeng/nginx:1.0 /bin/bash
此时x02容器也会有x01的内容

docker inspect 容器id
查看x01 与 x02的Mounts本地挂载地址是不是同一个。验证:是同一个

使用场景:多个mysql进行数据共享,
mysql01容器指定了-v ,
mysql02容器指定–volumes-from mysql01

注意(持久化):上面已经说过了,只有映射到了本地容器卷,容器删除之后,本地也会存在数据。

下面是之前的笔记,一次测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
docker run --name x01 -v /a:/a -d 镜像名称 
》》》这里容器x01和Linux都有/a文件夹,并共享。容器中没有会自动创建。
》》》此时x01,与Linux同步。其中一个修改,另外一个也会改。

docker run --name x02 --volumes-from x01 -d 镜像名称
》》》容器x02启动之后,会与x01的共享同一个容器卷,此时x02也会自动创建/a文件夹
》》》此时x01,x02,Linux三者同步。其中一个修改,另外两个也会改。

docker run --name x03 --volumes-from x01 -d 镜像名称
》》》此时,容器x02启动之后,同理也会建立/a文件夹
》》》此时x01,x02,x03,Linux四者同步。其中一个修改,另外三个也会改。

docker rm -f x01
》》》此时强制删除了容器x01,试问,此时x02,x03,Linux三者还会同步吗?
》》》答案:会。因为每个容器都会与a进行关联。
》》》如果x01修改了内容,会被内容同步到Linux,此时x02,x03再从x01进行同步。

关于挂载路径问题

1
2
3
4
5
匿名挂载:-v 容器路径

具名挂载:-v 卷名:容器路径

路径挂载:-v Linux路径:容器路径

不挂载,仅为了查看容器默认内容

1
2
3
4
5
6
7
------------------------docker run --name centos00 -itd centos
29ec6aa8221d3af617141d4ca02daa05bb8140c97d5a9e004cbee3e02bcb8134
------------------------docker exec -it centos00 ls -l /root
total 12
-rw-------. 1 root root 2328 Dec 4 2020 anaconda-ks.cfg
-rw-r--r--. 1 root root 435 Dec 4 2020 anaconda-post.log
-rw-------. 1 root root 2026 Dec 4 2020 original-ks.cfg

匿名挂载:容器路径不存在

》》》会把容器路径当做目录进行多层创建,类似于 mkdir -p 容器路径
》》》为该匿名卷随机取一个字符串当做卷名,在Linux本地创建目录/var/lib/docker/volumes/卷名/_data
》》》把容器路径下的内容挂载到Linux 路径的/var/lib/docker/volumes/卷名/_data。(此时复制是空,因为容器路径不存在,创建的是空目录,所以挂载也是空)
》》》聪明的会发现,他们两个目录的 inode号码是一致的。
》》》可以理解为两个目录的硬链接,而这个硬链接,是由Linux执行容器的,也就是先有容器,再根据容器建立硬链接/var/lib/docker/volumes/卷名/_data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
------------------------docker run --name centos01 -itd -v /abc/def/g centos
f914bb2b8bab9febd05e8c591b3a8784559530fe3b50dd1192c9fdc279354555
------------------------docker exec -it centos01 ls -li /abc/def/g
total 0
------------------------docker exec -it centos01 ls -lid /abc/def/g
33769521 drwxr-xr-x. 2 root root 6 Nov 29 14:27 /abc/def/g
------------------------docker inspect centos01 | grep "Mounts" -A 10
"Mounts": [
{
"Type": "volume", #===> 卷:相当于 ln 容器路径 Linux路径
"Name": "7a704e1da1cccb9aa565d98bcb7fe356c6e6ab6ffd0661a8d24dd99a82ab8735",
"Source": "/var/lib/docker/volumes/7a704e1da1cccb9aa565d98bcb7fe356c6e6ab6ffd0661a8d24dd99a82ab8735/_data",
"Destination": "/abc/def/g",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
------------------------ls -li /var/lib/docker/volumes/7a704e1da1cccb9aa565d98bcb7fe356c6e6ab6ffd0661a8d24dd99a82ab8735/_data
总用量 0
------------------------ls -lid /var/lib/docker/volumes/7a704e1da1cccb9aa565d98bcb7fe356c6e6ab6ffd0661a8d24dd99a82ab8735/_data
33769521 drwxr-xr-x. 2 root root 6 11月 29 22:27 /var/lib/docker/volumes/7a704e1da1cccb9aa565d98bcb7fe356c6e6ab6ffd0661a8d24dd99a82ab8735/_data
------------------------

匿名挂载:路径是文件

》》》启动容器报错:不能挂载已存在的文件,文件已经存在 /var/lib/docker/devicemapper/mnt/…

1
2
3
4
------------------------docker run --name centos02 -itd -v /root/original-ks.cfg centos
docker: Error response from daemon: cannot mount volume over existing file, file exists /var/lib/docker/devicemapper/mnt/30cb7a177083b773e054ee25a8157241603de0ad64172b74770129eebca8c881/rootfs/root/original-ks.cfg.
See 'docker run --help'.
------------------------docker ps -a | grep centos02 #===> 容器不存在

匿名挂载:路径是目录

》》》同匿名挂载:容器路径不存在类似,只不过匿名挂载:容器路径不存在会递归创建目录,
》》》把容器路径/root下的内容挂载到Linux路径下/var/lib/docker/volumes/卷名/_data
》》》此时/var/lib/docker/volumes/卷名/_data中是有数据的,因为/root下是存在数据的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
------------------------docker run --name centos03 -itd -v /root centos
9b182cfbda877b33fbd383f72a495dfdac82dc9e126bc521239cb81b7242f28e
------------------------docker exec -it centos03 ls -lid /root
51206590 dr-xr-x---. 2 root root 4096 Nov 29 14:31 /root
------------------------docker exec -it centos03 ls -li /root
total 12
52176647 -rw-------. 1 root root 2328 Dec 4 2020 anaconda-ks.cfg
50771008 -rw-r--r--. 1 root root 435 Dec 4 2020 anaconda-post.log
50771009 -rw-------. 1 root root 2026 Dec 4 2020 original-ks.cfg
------------------------docker inspect centos03 | grep "Mounts" -A 10
"Mounts": [
{
"Type": "volume", #===> 卷:相当于 ln 容器路径 Linux路径
"Name": "bacc6e4d08a666954ff932ad0afde99ac722c1400bea4da812d38a97605fe61b",
"Source": "/var/lib/docker/volumes/bacc6e4d08a666954ff932ad0afde99ac722c1400bea4da812d38a97605fe61b/_data",
"Destination": "/root",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
------------------------ls -lid /var/lib/docker/volumes/bacc6e4d08a666954ff932ad0afde99ac722c1400bea4da812d38a97605fe61b/_data
51206590 dr-xr-x---. 2 root root 4096 11月 29 22:31 /var/lib/docker/volumes/bacc6e4d08a666954ff932ad0afde99ac722c1400bea4da812d38a97605fe61b/_data
------------------------ls -li /var/lib/docker/volumes/bacc6e4d08a666954ff932ad0afde99ac722c1400bea4da812d38a97605fe61b/_data
总用量 12
52176647 -rw-------. 1 root root 2328 12月 5 2020 anaconda-ks.cfg
50771008 -rw-r--r--. 1 root root 435 12月 5 2020 anaconda-post.log
50771009 -rw-------. 1 root root 2026 12月 5 2020 original-ks.cfg

具名挂载:卷名规则

》》》具名挂载的名称规定:(至少两个字符)大小写字母或数字开头,内容只能包含大小写字母和数字,以及 _.- 下划线,小数点,减号 这三个特殊字符
》》》具名挂载与匿名挂载原理类似,只不过它为容器卷自定义了一个名称而已,在 docker volume ls 中方便查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
------------------------docker run --name centos04 -itd -v abc/def:/root centos
docker: Error response from daemon: create abc/def: "abc/def" includes invalid characters for a local volume name,
only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed. If you intended to pass a host directory, use absolute path.
See 'docker run --help'.
------------------------
------------------------
------------------------docker run --name centos04 -itd -v abcdef:/root centos
81534b1d4230bdc604f7dd689913f027552dbc9c19a2c1639506f09fea7bbab2
------------------------docker inspect centos04 | grep "Mounts" -A 10
"Mounts": [
{
"Type": "volume", #===> 卷:相当于 ln 容器路径 Linux路径
"Name": "abcdef",
"Source": "/var/lib/docker/volumes/abcdef/_data",
"Destination": "/root",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
------------------------ls -lid /var/lib/docker/volumes/abcdef/_data
275760 dr-xr-x---. 2 root root 4096 11月 29 22:40 /var/lib/docker/volumes/abcdef/_data
------------------------ls -li /var/lib/docker/volumes/abcdef/_data
总用量 12
275766 -rw-------. 1 root root 2328 12月 5 2020 anaconda-ks.cfg
275767 -rw-r--r--. 1 root root 435 12月 5 2020 anaconda-post.log
275768 -rw-------. 1 root root 2026 12月 5 2020 original-ks.cfg
------------------------
------------------------docker exec -it centos04 ls -lid /root
275760 dr-xr-x---. 2 root root 4096 Nov 29 14:40 /root
------------------------docker exec -it centos04 ls -li /root
total 12
275766 -rw-------. 1 root root 2328 Dec 4 2020 anaconda-ks.cfg
275767 -rw-r--r--. 1 root root 435 Dec 4 2020 anaconda-post.log
275768 -rw-------. 1 root root 2026 Dec 4 2020 original-ks.cfg

路径挂载:容器路径不存在

》》》把不存在的路径递归创建目录,并把Linux路径下的内容挂载到容器路径下
》》》ln Linux路径 容器路径,把 Linux 路径建立一个硬链接(容器路径),

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
------------------------ls -lid /root/
33595521 dr-xr-x---. 4 root root 4096 11月 29 22:44 /root/
------------------------ls -li /root/
总用量 4
33769504 -rw-r--r--. 1 root root 8 11月 29 20:53 a
------------------------
------------------------docker run --name centos05 -itd -v /root:/abc/def/g centos
601ee4bb2b187a7fca772bb5a20f853ce329c1a1b4e87a094108befc294ad694
------------------------docker exec -it centos01 ls -ld /abc/def/g
Error: No such container: centos01
------------------------
------------------------docker exec -it centos05 ls -lid /abc/def/g
33595521 dr-xr-x---. 4 root root 4096 Nov 29 14:44 /abc/def/g
------------------------docker exec -it centos05 ls -li /abc/def/g
total 4
33769504 -rw-r--r--. 1 root root 8 Nov 29 12:53 a
------------------------docker volume ls
DRIVER VOLUME NAME
------------------------docker inspect centos05 | grep "Mounts" -A 10
"Mounts": [
{
"Type": "bind", #===> 绑定:相当于 ln Linux路径 容器路径 (不同于匿名/具名挂载,注意:先后顺序)
"Source": "/root",
"Destination": "/abc/def/g",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
"Config": {

路径挂载:Linux路径不存在

》》》会递归创建 Linux目录,再 ln Linux路径 容器路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
------------------------docker run --name centos06 -itd -v /q/w:/root centos
77546c950bf2ba525438ba5e72083163ee2864f7228733184230733f916bf0d7
------------------------docker volume ls
DRIVER VOLUME NAME
------------------------docker inspect centos06 | grep "Mounts" -A 10
"Mounts": [
{
"Type": "bind",
"Source": "/q/w",
"Destination": "/root",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
"Config": {
------------------------ls -lid /q/w
50740894 drwxr-xr-x. 2 root root 6 11月 29 22:56 /q/w
------------------------ls -li /q/w
总用量 0
------------------------
------------------------docker exec -it centos06 ls -lid /root
50740894 drwxr-xr-x. 2 root root 6 Nov 29 14:56 /root
------------------------docker exec -it centos06 ls -li /root
total 0

路径挂载:Linux路径与容器路径一个是文件,一个是目录

》》》不可以创建,会报错:类型映射不正确

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#===> Linux路径是文件,容器路径是目录
------------------------docker run --name centos07 -itd -v /root/a:/root centos
8c4f5dc46b3ca6aeaceb7d86fbd7b480d2f0f59c68c8e57867bcf9c187263957
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449:
container init caused \"rootfs_linux.go:58: mounting \\\"/root/a\\\" to rootfs \\\"/var/lib/docker/devicemapper/mnt/709da0abae662f4fbc48392fdfceb29d4c8474eb76c4fc07b7cba96c5d25d347/rootfs\\\" at \\\"/var/lib/docker/devicemapper/mnt/709da0abae662f4fbc48392fdfceb29d4c8474eb76c4fc07b7cba96c5d25d347/rootfs/root\\\" caused \\\"not a directory\\\"\"": unknown:
Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type.
------------------------
------------------------
------------------------docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c4f5dc46b3c centos "/bin/bash" 10 seconds ago Created centos07
77546c950bf2 centos "/bin/bash" 5 minutes ago Up 5 minutes centos06

------------------------
------------------------docker ps -a | grep centos07
8c4f5dc46b3c centos "/bin/bash" About a minute ago Created centos07


#===> Linux路径是目录,容器路径是文件
------------------------docker run --name centos10 -itd -v /root:/root/original-ks.cfg centos
1769db024737bbb0c49d3d2fd6f682e3e24242118b206cefb80743ca9d9f539f
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449:
container init caused \"rootfs_linux.go:58: mounting \\\"/root\\\" to rootfs \\\"/var/lib/docker/devicemapper/mnt/5ffbc73047e998d3bd4c11c4277fcc157f758744c586b5e08070982888aaf453/rootfs\\\" at \\\"/var/lib/docker/devicemapper/mnt/5ffbc73047e998d3bd4c11c4277fcc157f758744c586b5e08070982888aaf453/rootfs/root/original-ks.cfg\\\" caused \\\"not a directory\\\"\"":
unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type.

路径挂载:Linux路径是文件/目录,容器路径不存在

》》》依旧如此,ln Linux路径 容器路径,只不过 容器路径中不存在的目录会自动创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
------------------------ls -li /root/
总用量 4
33769504 -rw-r--r--. 1 root root 8 11月 29 20:53 a
------------------------docker run --name centos08 -itd -v /root/a:/root/a/b/c centos
7b544fd1a3d264cb51591be105a73fb54150b76d1690bc651029dca420a800e1
------------------------docker exec -it centos08 ls -li /root/a/b/c
33769504 -rw-r--r--. 1 root root 8 Nov 29 12:53 /root/a/b/c


------------------------
------------------------docker run --name centos09 -itd -v /root/:/root/a/b/c centos
beee9b627dfdce94c9db47a77a5d5a7c6b102888f07717e86b646be9b4c1a951
------------------------docker exec -it centos09 ls -li /root/a/b/c
total 4
33769504 -rw-r--r--. 1 root root 8 Nov 29 12:53 a

路径挂载:Linux路径不存在,容器路径是文件/目录

》》》当Linux路径不存在时,容器路径是只能是目录,而不可以是文件,会报错:类型映射不正确

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#===> Linux路径不存在,容器路径是目录
------------------------docker run --name centos11 -itd -v /abc/def/g:/root centos
08a0dbc96782f283a2942ae253edccc4158579fad5f75befb5fca2562b52df97
------------------------
------------------------
------------------------
------------------------ls -lid /abc/def/g
17410142 drwxr-xr-x. 2 root root 6 11月 29 23:22 /abc/def/g
------------------------ls -li /abc/def/g
总用量 0
------------------------
------------------------docker exec -it centos11 ls -lid /root
17410142 drwxr-xr-x. 2 root root 6 Nov 29 15:22 /root
------------------------docker exec -it centos11 ls -li /root
total 0

#===> Linux路径不存在,容器路径是文件
------------------------docker run --name centos12 -itd -v /qwe/rty/u:/root/original-ks.cfg centos
a89cbf8d9c3a5219be0d7dab7d19573be652c1eecf2365ed286521c21f6be9ff
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449:
container init caused \"rootfs_linux.go:58: mounting \\\"/qwe/rty/u\\\" to rootfs \\\"/var/lib/docker/devicemapper/mnt/11e13a886442d6a8ed058a25ee732fec869300975536c1e8895a1ad066a55082/rootfs\\\" at \\\"/var/lib/docker/devicemapper/mnt/11e13a886442d6a8ed058a25ee732fec869300975536c1e8895a1ad066a55082/rootfs/root/original-ks.cfg\\\" caused \\\"not a directory\\\"\"": unknown:
Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type.