Volume
Volume是容器数据卷。我们经常创建删除一些容器,但有时候需要保留容器中的一些数据,这时候就用到了Volume。它也是容器之间数据共享的技术,可以将容器中产生的数据同步到本地。实际就是把容器中的目录挂载到运行着容器的服务器或个人电脑上。
挂载命令-v
第一种挂载volume的方式是通过命令-v
来挂载。
指定路径挂载
类似于-p 主机端口:容器内端口
,-v
也是-v 主机目录:容器内目录
。这种方式是指定路径挂载。
在主机建一个/mainHome目录,我有一个centos镜像,用它跑起一个容器来,将容器的/home目录映射到主机/mainHome目录。
root@KitDevVps:~# mkdir mainHome
root@KitDevVps:~# pwd
/root
root@KitDevVps:~# docker run -it -v /root/mainHome:/home centos /bin/bash
[root@b486ed5aa77f /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@b486ed5aa77f /]# cd /home/
[root@b486ed5aa77f home]# ls
[root@b486ed5aa77f home]# touch test.txt
[root@b486ed5aa77f home]# ls
test.txt
[root@b486ed5aa77f home]# exit
exit
root@KitDevVps:~# ls /root/mainHome/
test.txt
可以看到映射之后,我进入容器内,在它的/home下创建了一个test.txt,退出容器回到主机的/root/mainHome下,发现也已经有了一个test.txt文件。
目前我们了解了修改容器内文件可以让容器外面挂载到的目录出现变化。我们尝试在容器外编辑这个test.txt文件,然后进容器内查看。虽然我们基本已经清楚这是多此一举,但还是尝试一下。
root@KitDevVps:~# cd /root/mainHome/
root@KitDevVps:~/mainHome# vim test.txt
root@KitDevVps:~/mainHome# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b486ed5aa77f centos "/bin/bash" 5 minutes ago Exited (0) 4 minutes ago boring_cerf
242fdc2bba7d centos "-it /bin/bash" 6 minutes ago Created optimistic_dubinsky
1cdd55fd90c5 nginx "/docker-entrypoint.…" 11 hours ago Up 7 hours 0.0.0.0:80->80/tcp nginx1
7d2fd4e741ba hello-world "/hello" 13 hours ago Exited (0) 13 hours ago elastic_goldstine
root@KitDevVps:~/mainHome# docker start b486ed5aa77f
b486ed5aa77f
root@KitDevVps:~/mainHome# docker exec -it b486ed5aa77f /bin/bash
[root@b486ed5aa77f /]# cat /home/test.txt
Hello Volume!
可以看到容器内的test.txt的内容也随之发生了变化。而且我们之前exit
时,实际上容器就已经stop了,我们是在容器停止之后修改了本机的test.txt文件,重新运行起容器,发现容器内的test.txt文件也发生了变化。可以说是非常灵活。
注意,如果运行容器时没有使用-d,没有让其后台运行,在容器内时,可以使用ctrl+p+q来退出容器,此时容器依旧会在运行,使用exit退出,我预计它不会运行,但容器也会继续运行。这一块跟我前面结果有出入,让我摸不到头脑。后面我又有一次没有-d,exit后容器stop了,ctrl+p+q没有stop。-d后exit容器也没有stop。现在的结论就是:
- 没有-d,使用exit,容器会stop
- 没有-d,使用ctrl+p+q,容器不会stop
- 没有-d,使用exit退出,容器stop,再使用
docker start 容器名
启动,容器依旧会在后台运行 - 没有-d,使用ctrl+p+q退出,容器不会stop
- 有-d,使用exit,容器不会stop
- 有-d,使用ctrl+p+q,容器不会stop
- 有-d,使用exit退出,容器stop,再使用
docker start 容器名
启动,容器依旧会在后台运行,使用ctrl+p+q - 有-d,使用ctrl+p+q退出,容器不会stop
可以使用docker inspect <容器id>
来查看容器详细信息,其中会包括卷挂载的目录等。
如果我想用docker搞一个nginx,又不想一遍一遍地进入容器修改配置文件,因为我可能随时删除容器。此时就可以用这种方式。每次运行新容器,只需要把主机存放配置文件的目录挂载到容器存放配置文件的目录即可。因为即使删掉容器,主机的目录和里面的内容不会丢失。
注意:可以同时挂载多个目录,格式:-v 主机目录1:容器内目录1 -v 主机目录2:容器内目录2 -v...
如果只写-v 容器内目录
,是匿名挂载的格式,会自动在主机生成目录。
docker volume ls
是查看所有本机的卷的指令,可以用docker volume --help
来查看更多用法。
root@KitDevVps:~# docker volume ls
DRIVER VOLUME NAME
local sqlvolume
不知道为什么,竟然不显示之前我挂载的mainHome,可能是那个只是目录的映射,不是卷,用docker volume create
创建出来的才是卷。
尝试一下匿名挂载和具名挂载:
具名挂载
具名挂载的命令:-v 卷名:容器内路径
。卷名前面如果加上个“/”,就会变成指定路径挂载。注意区分。
具名挂载:
root@KitDevVps:~# docker run -d -P --name centos01 -v centos01:/home centos
775b213506eb2bc06228ac25d2f8e36f5abfccaba80658accc072a7fd7af6879
root@KitDevVps:~# docker volume ls
DRIVER VOLUME NAME
local centos01
local sqlvolume
docker run -d -P --name centos01 -v centos01:/home centos
这行命令中,-d是后台运行,-P大写P是随机指定端口,-v centos01:/home
的centos01
是卷名,不是主机目录,这里很容易跟主机目录混淆,要留心。冒号后面是容器内目录。我在指令中加了-d让它后台运行,但docker自动把这个镜像关闭了,原因似乎是docker理解这个容器没用了,就自动关掉了。下次尝试不加-d。
删掉容器,看看volume还在不在:
root@KitDevVps:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
775b213506eb centos "/bin/bash" 37 seconds ago Exited (0) 35 seconds ago centos01
1cdd55fd90c5 nginx "/docker-entrypoint.…" 21 hours ago Up 18 hours 0.0.0.0:80->80/tcp nginx1
7d2fd4e741ba hello-world "/hello" 24 hours ago Exited (0) 24 hours ago elastic_goldstine
root@KitDevVps:~# docker rm centos01
centos01
root@KitDevVps:~# docker volume ls
DRIVER VOLUME NAME
local centos01
local sqlvolume
发现删掉之后,数据卷还在,这符合我们的需求。
匿名挂载
匿名挂载:
root@KitDevVps:~# docker run -P --name centos01 -v /home centos
root@KitDevVps:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cdd55fd90c5 nginx "/docker-entrypoint.…" 21 hours ago Up 18 hours 0.0.0.0:80->80/tcp nginx1
root@KitDevVps:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bca038e5ea33 centos "/bin/bash" 45 seconds ago Exited (0) 43 seconds ago centos01
1cdd55fd90c5 nginx "/docker-entrypoint.…" 21 hours ago Up 18 hours 0.0.0.0:80->80/tcp nginx1
7d2fd4e741ba hello-world "/hello" 24 hours ago Exited (0) 24 hours ago elastic_goldstine
root@KitDevVps:~# docker volume ls
DRIVER VOLUME NAME
local 847c90a1bdcdcfa65d8fd316ddf53816e223b185125d519152c4a2260323b7e9
local centos01
local sqlvolume
可以看到匿名挂载的volume name是随机的码。但有一个其他的问题,是我明明没有加-d让它后台运行,为什么还是自动关掉了。查看日志发现日志也为空。实在不知道该如何解决自动stop容器的问题。
ro和rw
看以下命令:
docker run -it -v /root/mainHome:/home:ro centos /bin/bash
docker run -it -v /root/mainHome:/home:rw centos /bin/bash
如果在容器内路径后面加上:ro
或:rw
,是对权限的配置,约束的是容器内的权限。ro只能从外部改变,不能从容器内部改变。默认就是rw,容器内对卷目录下的文件也可读可写。
卷的其他操作以及卷的路径
这个问题先一放,看一下docker volume
命令怎么用:
root@KitDevVps:~# docker volume -h
Flag shorthand -h has been deprecated, please use --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
Run 'docker volume COMMAND --help' for more information on a command.
可以知道创建、删除等操作。主要看一下inspect:
root@KitDevVps:~# docker volume ls
DRIVER VOLUME NAME
local 847c90a1bdcdcfa65d8fd316ddf53816e223b185125d519152c4a2260323b7e9
local centos01
root@KitDevVps:~# docker volume inspect 847c90a1bdcdcfa65d8fd316ddf53816e223b185125d519152c4a2260323b7e9
[
{
"CreatedAt": "2020-07-04T01:53:46Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/847c90a1bdcdcfa65d8fd316ddf53816e223b185125d519152c4a2260323b7e9/_data",
"Name": "847c90a1bdcdcfa65d8fd316ddf53816e223b185125d519152c4a2260323b7e9",
"Options": null,
"Scope": "local"
}
]
现在查看的是匿名卷,可以看到路径在"Mountpoint"那一栏。docker所有的卷如果没有指定详细路径,都会放在/var/lib/docker/volumes/这个目录下,而所有的数据都在/_data下。我们看一下里面有什么:
root@KitDevVps:~# ls /var/lib/docker/volumes/847c90a1bdcdcfa65d8fd316ddf53816e223b185125d519152c4a2260323b7e9/_data/
root@KitDevVps:~#
看来暂时还什么都没有,因为我挂载的是home目录,而且这个镜像也已经被我删了,暂时没法进它的home进行操作。我重新搞一个。为什么这次我可以运行起这个容器而不自动退出,可以看如何解决容器创建出来自动停止的问题:
root@KitDevVps:~# docker run -P -d -it --name centos01 -v centos01Volume:/home centos
e087f8443ee1f62dd68950e3f61fa039852b2dfee18a117019951b236a430548
root@KitDevVps:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e087f8443ee1 centos "/bin/bash" 4 seconds ago Up 2 seconds centos01
1cdd55fd90c5 nginx "/docker-entrypoint.…" 23 hours ago Up 19 hours 0.0.0.0:80->80/tcp nginx1
root@KitDevVps:~# docker exec -it e087f8443ee1 /bin/bash
[root@e087f8443ee1 /]# touch /home/test.txt
[root@e087f8443ee1 /]# ls /home/
test.txt
[root@e087f8443ee1 /]# exit
exit
root@KitDevVps:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e087f8443ee1 centos "/bin/bash" 3 minutes ago Up 3 minutes centos01
1cdd55fd90c5 nginx "/docker-entrypoint.…" 23 hours ago Up 19 hours 0.0.0.0:80->80/tcp nginx1
root@KitDevVps:~# ls /var/lib/docker/volumes/centos01Volume/_data/
test.txt
可以看到/var/lib/docker/volumes/centos01Volume/_data/路径下有映射的容器内/home/目录下的文件。同时注意,我在运行这个容器时使用了-d和-it,后面我exit出容器后,容器依然是在运行的。后面我自己创建的镜像run出来的容器,没有使用-d,使用exit或ctrl+p+q退出容器后,依旧也在后台运行,这让我怀疑-d除了返回id外到底有什么用。后来通过实践得知,加了-d后,run出容器来,并不直接进入容器,而是回到了本机。不加-d则会直接进入容器。
再看一下主机的/var/lib/docker下有什么:
root@KitDevVps:~# ls /var/lib/docker/
builder buildkit containers image network overlay2 plugins runtimes swarm tmp trust volumes
其中containers是docker的容器,image是docker的镜像,network是docker的网络,plugins是插件,volumes就是卷。
如何解决容器创建出来自动停止的问题(重要)
我尝试运行镜像的时候与镜像交互:
docker run -d -P -it --name centos01 centos
d59e9785a1212280342817d9e5c49ca126d2eda5af8cf1ef8da194570ecf49ce
root@KitDevVps:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d59e9785a121 centos "/bin/bash" 5 seconds ago Up 3 seconds centos01
1cdd55fd90c5 nginx "/docker-entrypoint.…" 22 hours ago Up 19 hours 0.0.0.0:80->80/tcp nginx1
root@KitDevVps:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d59e9785a121 centos "/bin/bash" 8 seconds ago Up 7 seconds centos01
1cdd55fd90c5 nginx "/docker-entrypoint.…" 22 hours ago Up 19 hours 0.0.0.0:80->80/tcp nginx1
同时使用-d和-it,发现容器没有自杀,正常启动了。
尝试不使用-d,只使用-it:
root@KitDevVps:~# docker run -P -it --name centos01 centos
[root@53df37df4c1e /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
发现直接进入了镜像的命令行。输入exit退出:
[root@53df37df4c1e /]# exit
exit
root@KitDevVps:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cdd55fd90c5 nginx "/docker-entrypoint.…" 22 hours ago Up 19 hours 0.0.0.0:80->80/tcp nginx1
发现镜像也自动stop了。如果运行容器时同时使用-d和-it,即使exit退出容器,容器依然会在运行。
还有的容器自动停止是其他原因,可以使用docker logs 容器id
查看日志。比如sqlserver的容器,自动stop的原因可能是服务器的内存不满足它配置的需求:
root@KitDevVps:~# docker run --name mssql01 -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=******' -e 'MSSQL_PID=Express' -p 1433:1433 -v sqlvolume:/var/opt/mssql -d -it mcr.microsoft.com/mssql/server
7664784740e200dcb20d02d3f93369023f9ff3438b9aa80ccfc138df3a1f46ee
root@KitDevVps:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1cdd55fd90c5 nginx "/docker-entrypoint.…" 22 hours ago Up 19 hours 0.0.0.0:80->80/tcp nginx1
root@KitDevVps:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7664784740e2 mcr.microsoft.com/mssql/server "/opt/mssql/bin/perm…" 8 seconds ago Exited (1) 7 seconds ago mssql01
53df37df4c1e centos "/bin/bash" 4 minutes ago Exited (130) About a minute ago centos01
1cdd55fd90c5 nginx "/docker-entrypoint.…" 22 hours ago Up 19 hours 0.0.0.0:80->80/tcp nginx1
7d2fd4e741ba hello-world "/hello" 25 hours ago Exited (0) 25 hours ago elastic_goldstine
root@KitDevVps:~# docker logs 7664784740e2
SQL Server 2019 will run as non-root by default.
This container is running as user mssql.
To learn more visit https://go.microsoft.com/fwlink/?linkid=2099216.
sqlservr: This program requires a machine with at least 2000 megabytes of memory.
/opt/mssql/bin/sqlservr: This program requires a machine with at least 2000 megabytes of memory.
日志中写了它至少需要2000M内存,我的服务器就是2000M内存,看来还不够。可能要4000M内存的服务器才能玩它。
Dockerfile挂载卷的方式
可以使用DockerFile来挂载卷。DockerFile也是重要的Docker知识点,我一直没搞懂,下次尝试搞懂它,这次先用它挂载卷。
Dockerfile看起来就像是构建docker镜像的配置文件,利用它可以生成镜像。试一下。
先开一个目录用来写Dockerfile和存放生成的镜像:
root@KitDevVps:~# cd /home/
root@KitDevVps:/home# mkdir dockerfile-volume-test
root@KitDevVps:/home# ls
dockerfile-volume-test
root@KitDevVps:/home# cd dockerfile-volume-test/
root@KitDevVps:/home/dockerfile-volume-test#
这个目录是/home/dockerfile-volume-test。在里面写一个dockerfile1,然后在里面写一些脚本。通过这些脚本可以生成一个docker镜像。脚本是一个个的命令,每个命令都是一层:
# 以centos镜像为基础
FROM centos
# 挂载卷,在镜像生成的时候就把卷挂载出来,可以挂载多个目录,目录都会在容器中生成,在本机上是以匿名挂载的方式在默认的位置。当然要run出容器来才会挂载,只build镜像当然不会挂载
VOLUME ["volume1","volume2"]
# 写一个命令行,输出一条语句,证明脚本运行到了这里,镜像构建成功
CMD echo "build succeed"
# 构建完之后,我们进入容器时希望走bash
CMD /bin/bash
dockerfile写好了,使用docker build
命令构建镜像:
root@KitDevVps:/home/dockerfile-volume-test# docker build -f dockerfile1 -t kit/centos .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 831691599b88
Step 2/4 : VOLUME ["volume1","volume2"]
---> Running in f634ab6900f1
Removing intermediate container f634ab6900f1
---> 10d1359b311e
Step 3/4 : CMD echo "build succeed"
---> Running in e505fce33f96
Removing intermediate container e505fce33f96
---> bad661d7a8e7
Step 4/4 : CMD /bin/bash
---> Running in 59efa3a8897d
Removing intermediate container 59efa3a8897d
---> 9347f3c0dcd9
Successfully built 9347f3c0dcd9
Successfully tagged kit/centos:latest
看一下第一行的命令:
-f 后加dockerfile的地址。
-t就是target,就是生成的镜像的名字。注意开头不要有/,会被识别成目录。最后可以用冒号":"来指定tag,可以写成1.0,1.1等,不写的话默认就是latest。
最后的“.”是指生成在当前目录下,也可以换成指定的目录。
再看一下build的过程,第一步是拿到基础镜像,第二步是挂载,第三步写出了我们刚才写的CMD命令,第四步进入了/bin/bash。
我再尝试构建一个镜像,跟这个名字相同,tag为1.0,并且最后用绝对路径指定镜像生成的路径:
root@KitDevVps:/home/dockerfile-volume-test# docker build -f dockerfile1 -t kit/centos:1.0 /home/dockerfile-volume-test/
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 831691599b88
Step 2/4 : VOLUME ["volume1","volume2"]
---> Using cache
---> 10d1359b311e
Step 3/4 : CMD echo "build succeed"
---> Using cache
---> bad661d7a8e7
Step 4/4 : CMD /bin/bash
---> Using cache
---> 9347f3c0dcd9
Successfully built 9347f3c0dcd9
Successfully tagged kit/centos:1.0
root@KitDevVps:/home/dockerfile-volume-test# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kit/centos 1.0 9347f3c0dcd9 4 minutes ago 215MB
kit/centos latest 9347f3c0dcd9 4 minutes ago 215MB
centos latest 831691599b88 2 weeks ago 215MB
mcr.microsoft.com/mssql/server latest d2520a2df464 2 weeks ago 1.51GB
nginx latest 2622e6cca7eb 3 weeks ago 132MB
hello-world latest bf756fb1ae65 6 months ago 13.3kB
可以看到两个镜像名字相同,只有版本号不同,连id也相同。用id删除镜像的话估计就全都删除了,我尝试能不能用名字加tag只删除其中一个。先删latest:
root@KitDevVps:/home/dockerfile-volume-test# docker rmi kit/centos:latest
Untagged: kit/centos:latest
root@KitDevVps:/home/dockerfile-volume-test# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
kit/centos 1.0 9347f3c0dcd9 2 minutes ago 215MB
centos latest 831691599b88 2 weeks ago 215MB
mcr.microsoft.com/mssql/server latest d2520a2df464 2 weeks ago 1.51GB
nginx latest 2622e6cca7eb 3 weeks ago 132MB
hello-world latest bf756fb1ae65 6 months ago 13.3kB
我试验了两次,rmi后的容器名称加上":latest"和不加,均能删掉latest,但不删掉1.0。看来对于id相同的容器,可以使用rmi 容器名加tag的方式来删除。
root@KitDevVps:/home/dockerfile-volume-test# docker rmi kit/centos:1.0
Untagged: kit/centos:1.0
Deleted: sha256:9347f3c0dcd9dd7a6650e73a329ac77582565f5e640cb2b10c89bb90173dde4e
Deleted: sha256:bad661d7a8e75bf3fad12348712826a57571e53d95c77acc4c1b6aa80032a3e6
Deleted: sha256:10d1359b311e2fe98e728368d44778aae5083f9e836f883a7c423b03fa0ad93b
root@KitDevVps:/home/dockerfile-volume-test# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 831691599b88 2 weeks ago 215MB
mcr.microsoft.com/mssql/server latest d2520a2df464 2 weeks ago 1.51GB
nginx latest 2622e6cca7eb 3 weeks ago 132MB
hello-world latest bf756fb1ae65 6 months ago 13.3kB
删掉了。我重新构建出1.0来,尝试run起来一个容器并且进入。
root@KitDevVps:/home/dockerfile-volume-test# docker run -it kit/centos:1.0 /bin/bash
[root@6becde880c2b /]#
[root@6becde880c2b /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume1 volume2
可以看到不但成功进入了我们的容器,ls了一下发现容器内根目录有volume1 volume2两个目录,我们在run出这个容器的时候名没有添加-v,也就是说这两个目录是我们通过在dockerfile中写命令,生成容器时来自动挂载的。
实际上不输入/bin/bash也可以进入容器,我猜测是前面dockerfile的CMD /bin/bash
起了作用。
我们进入volume1,创建一个文件test.txt,然后另开一个终端看一下主机中有没有以匿名挂载的方式挂载到默认路径,顺便看看其中有没有test.txt:
[root@6becde880c2b /]# touch volume1/test.txt
[root@6becde880c2b /]# ls volume1
test.txt
另外开一个终端:
root@KitDevVps:~# ls /var/lib/docker/volumes/
8f76e936d3b3b0f119ca3424578a0dc2f23b19060017fdc2b84d4e2eede1f1e4 acd4c09b3f77f070e9a900cc33e3326f30122ce97383ed188335d805ade381b6 metadata.db
root@KitDevVps:~# ls /var/lib/docker/volumes/8f76e936d3b3b0f119ca3424578a0dc2f23b19060017fdc2b84d4e2eede1f1e4/_data/
root@KitDevVps:~# ls /var/lib/docker/volumes/acd4c09b3f77f070e9a900cc33e3326f30122ce97383ed188335d805ade381b6/_data/
test.txt
可以看到默认路径下有两个匿名的挂载目录,其中acd开头的目录下的_data中存在一个我们创建的test.txt,显然它就是容器内的volume1。
除了记住这个默认路径,还可以通过docker imspect 容器id
的方式查看容器的详细信息来找到挂载路径:
root@KitDevVps:~# docker inspect 6becde880c2b
...
"Mounts": [
{
"Type": "volume",
"Name": "8f76e936d3b3b0f119ca3424578a0dc2f23b19060017fdc2b84d4e2eede1f1e4",
"Source": "/var/lib/docker/volumes/8f76e936d3b3b0f119ca3424578a0dc2f23b19060017fdc2b84d4e2eede1f1e4/_data",
"Destination": "volume2",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "acd4c09b3f77f070e9a900cc33e3326f30122ce97383ed188335d805ade381b6",
"Source": "/var/lib/docker/volumes/acd4c09b3f77f070e9a900cc33e3326f30122ce97383ed188335d805ade381b6/_data",
"Destination": "volume1",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
...
我们构建镜像常常是自己使用或者公司内部使用,可能常常需要用这种方式自动挂载,而不使用-v。
数据卷容器(容器之间数据卷共享)
还可以通过容器之间数据卷共享的方式在多个容器之间共享数据,比如有多个mssql,就能共享数据库中的数据。
首先需要一个父容器,还需要一个子容器去挂载它,实现数据同步。使用--volumes-from
命令。
先删除主机上所有的卷:
root@KitDevVps:~# docker volume rm $(docker volume ls -q)
8f76e936d3b3b0f119ca3424578a0dc2f23b19060017fdc2b84d4e2eede1f1e4
0692a62975fed8394be202bac773ff8fe9a53f4a406d34b8eb8f8fba2827d393
acd4c09b3f77f070e9a900cc33e3326f30122ce97383ed188335d805ade381b6
bfe36976df800a733703b69fcf6b7bea95e68fc554588756c241705ea83a29a2
root@KitDevVps:~# docker volume ls
DRIVER VOLUME NAME
尝试创建三个容器,实现数据共享,使用我们自己build的镜像来做。先运行起一个容器,取名docker01,作为父容器,顺便进入容器内部:
root@KitDevVps:~# docker run -it --name docker01 kit/centos:1.0
[root@dcd5c3b67f9b /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume1 volume2
发现依旧生成了volume1 volume2。使用ctrl+p+q或exit退出容器(但后面我创建docker02时使用exec退出它,容器就自动停止运行了。),然后再创建它的子容器docker02,在run命令中加上--volumes-from docker01
,仿佛是继承了docker01的volumes:
root@KitDevVps:~# docker run -it --name docker02 --volumes-from docker01 kit/centos:1.0
[root@0b900529dd5b /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume1 volume2
发现02中依旧有volume1 volume2。可以使用ctrl+p+q退出容器,容器依旧还在后台运行。此时查看主机的数据卷,发现还是只有docker01的那两个数据卷:
root@KitDevVps:~# docker volume ls
DRIVER VOLUME NAME
local 62208e194cb6d971e0e1610f603ac8ae90a2df8d3b5b8c198fd1523a62baf537
local d7fc935ed1bf694e9efbf88cf20722d704201a1fd86d87ea0a6e17840301f830
为了验证两个容器数据是否互通,另开一个终端,使用docker attach
进入01,修改volume1,然后进入02查看是否变化。使用docker attach
比docker exec
似乎更简单:
root@KitDevVps:~# docker attach docker01
[root@dcd5c3b67f9b /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var volume1 volume2
[root@dcd5c3b67f9b /]# touch volume1/test.txt
[root@dcd5c3b67f9b /]# ls volume1
test.txt
再看docker02:
root@KitDevVps:~# docker attach docker02
[root@0b900529dd5b /]# ls volume1
test.txt
果然也存在了这个文件。再在02中touch一个,看看01有没有改变:
[root@0b900529dd5b /]# touch volume1/test2.txt
[root@0b900529dd5b /]# ls volume1
test.txt test2.txt
去01中看:
[root@dcd5c3b67f9b /]# ls volume1
test.txt test2.txt
果然也存在了。
下面再尝试以下创建docker03 --volumes-from 01,再创建docker04 --volumes-from 02,看看可不可以:
root@KitDevVps:~# docker run -d -it --name docker03 --volumes-from docker01 kit/centos:1.0
51ce86e015fd6b86651f28ecf66e924082fd86fd67ac15af5968ebe3706a09f4
root@KitDevVps:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
51ce86e015fd kit/centos:1.0 "/bin/sh -c /bin/bash" 9 seconds ago Up 8 seconds docker03
0b900529dd5b kit/centos:1.0 "/bin/sh -c /bin/bash" 15 minutes ago Up 15 minutes docker02
dcd5c3b67f9b kit/centos:1.0 "/bin/sh -c /bin/bash" 26 minutes ago Up 26 minutes docker01
1cdd55fd90c5 nginx "/docker-entrypoint.…" 31 hours ago Up 27 hours 0.0.0.0:80->80/tcp nginx1
root@KitDevVps:~# docker attach docker03
[root@51ce86e015fd /]# ls volume1
test.txt test2.txt
03是挂载了01,数据同步了。再创建04挂载02试试:
root@KitDevVps:~# docker run -d -it --name docker04 --volumes-from docker02 kit/centos:1.0
018a33472a829fcc93c54a5259397800459c78d6af87db24a208a333cd5bc0b2
root@KitDevVps:~# docker attach docker04
[root@018a33472a82 /]# ls volume1
test.txt test2.txt
也是可以的。此时查看主机数据卷:
root@KitDevVps:~# docker volume ls
DRIVER VOLUME NAME
local 62208e194cb6d971e0e1610f603ac8ae90a2df8d3b5b8c198fd1523a62baf537
local d7fc935ed1bf694e9efbf88cf20722d704201a1fd86d87ea0a6e17840301f830
还是那两个。即使把docker01删掉,其它容器的数据也不会丢失,删别的也一样。只要有容器还在用这些数据,就不会丢失。同时,因为我们使用-v或者dockerfile等方式持久化到了本地,所以就算容器全删掉,主机上的卷也不会丢失,卷内创建的文件也还在,这是我实验过的。如果2断了,1和3依旧是挂载着的,可以看出似乎不是链式的。
上图是狂神的教程里的图,指容器卷共享是互相拷贝的概念,而不是共用同一块存储的概念。
在实际项目中可以用于多个redis或者mssql等实现数据共享。也可以做集群的时候进行配置文件共享。
有没有-d与exit和ctrl+p+q两种退出方式之间的关系(难点)
有-d指的是run出容器的时候添加了-d这个option。
- 没有-d,使用exit,容器会stop
- 没有-d,使用ctrl+p+q,容器不会stop
- 没有-d,使用exit退出,容器stop,再使用
docker start 容器名
启动,容器依旧会在后台运行 - 没有-d,使用ctrl+p+q退出,容器不会stop
- 有-d,使用exit,容器不会stop
- 有-d,使用ctrl+p+q,容器不会stop
- 有-d,使用exit退出,容器stop,再使用
docker start 容器名
启动,容器依旧会在后台运行 - 有-d,使用ctrl+p+q退出,容器不会stop
以上结论并不全对,因为我后来run一个ubuntu的时候,出现了上面之外的情况,总之我选择以后只使用ctrl+p+q来退出容器。