前言
当我们启动容器后会产生各种数据,这些数据都存放在容器内,一旦不小心执行了docker rm 命令就会删容器导致数据丢失,在生产环境中必须对docker容器产生的数据进行持久化,而且也会涉及到多个容器数据共享的问题。为了解决上述问题我们可以使用docker的
数据卷技术
。
什么是数据卷
数据卷(Data Volumes)是一个可供容器使用的特殊目录,通过这个目录可以将容器内的数据直接映射到宿主机上,即使不小心删除了容器,容器产生的数据也保存在了宿主机上了。比如我可以将容器路径 /usr/local/data 映射到宿主机 /soft/docker/data路径上,如下图所示:
通过数据卷技术我们可以完成 容器数据的持久化与 容器之间的数据共享 。
创建数据卷
docker提供了 volume
命令用于管理数据卷,我们可以使用 help查看命令的使用帮助:
[root@VM-0-10-centos ~]# 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
Run 'docker volume COMMAND --help' for more information on a command.
使用create命令可以创建一个容器卷如下所示:
[root@VM-0-10-centos ~]# docker volume create my-volume
my-volume
使用ls命令可以查看当前容器存在的所有卷:
[root@VM-0-10-centos ~]# docker volume ls
DRIVER VOLUME NAME
local my-volume
create命令创建的卷默认在 宿主机 /var/lib/docker/volumes路径下,可以使用 tree
命令查看:
[root@VM-0-10-centos volumes]# tree /var/lib/docker/volumes/
/var/lib/docker/volumes/
|-- backingFsBlockDev
|-- metadata.db
`-- my-volume
`-- _data
2 directories, 2 files
使用inspect命令可以查看数据卷详情:
[root@VM-0-10-centos volumes]# docker volume inspect my-volume
[
{
"CreatedAt": "2021-12-25T21:22:14+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-volume/_data",
"Name": "my-volume",
"Options": {},
"Scope": "local"
}
]
使用prune命令清理无用的容器:
[root@VM-0-10-centos volumes]# docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
my-volume
Total reclaimed space: 0B
使用rm命令删除容器卷:
- 创建容器
## 创建容器卷
[root@VM-0-10-centos volumes]# docker volume create my-volume
my-volume
## 列出所有的容器卷
[root@VM-0-10-centos volumes]# docker volume ls
DRIVER VOLUME NAME
local my-volume
使用 -q 可以只列出容器卷名称:
[root@VM-0-10-centos volumes]# docker volume ls -q
my-volume
删除单个容器卷:
[root@VM-0-10-centos volumes]# docker volume rm my-volume
my-volume
批量删除所有容器卷
[root@VM-0-10-centos volumes]# docker volume create my-volume
my-volume
## 删除所有容器卷
[root@VM-0-10-centos volumes]# docker volume ls -q | xargs docker volume rm
my-volume
绑定数据卷
上面我们使用 volume命令来管理数据卷外,还可以在创建容器时创建容器卷并同时建立起容器卷与宿主机路径的映射,首先我们下载一个nginx的镜像来演示容器卷的绑定:
- 下载nginx镜像
[root@VM-0-10-centos volumes]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete
f3409a9a9e73: Pull complete
9919a6cbae9c: Pull complete
fc1ce43285d7: Pull complete
1f01ab499216: Pull complete
13cfaf79ff6d: Pull complete
Digest: sha256:366e9f1ddebdb844044c2fafd13b75271a9f620819370f8971220c2b330a9254
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
- 运行镜像并挂载数据卷
可以在创建容器的时候可以建立宿主机路径与容器内容器的映射:例如映射nginx容器的html目录:例如映射宿主机路径 /soft/data/docker/html
与 /soft/nginx/html
[root@VM-0-10-centos html]# docker run -d --name nginx -P -v /soft/data/docker/html:/soft/nginx/html nginx
e0c7ed8c9999b4121c3c3a62eb23f7579a145ecbbc3885ecfe461fad1a8842cc
创建test.html:
vim test.html
## 添加如下内容:
<<html>
<head>
<script type="text/javascript">
function alertIndex()
{
var x=document.getElementById("mySelect").selectedIndex;
var y=document.getElementsByTagName("option");
alert(y[x].text + " has the index of: " + y[x].index);
}
</script>
</head>
<body>
<form>
Select your favorite fruit:
<select id="mySelect">
<option>Apple</option>
<option>Orange</option>
<option>Pineapple</option>
<option>Banana</option>
</select>
<br />
<br />
<input type="button" onclick="alertIndex()"
value="Show index of the chosen fruit">
</form>
</body>
</html>
可以查看当前路径下有test.html:
[root@VM-0-10-centos html]# ll
total 4
-rw-r--r-- 1 root root 555 Dec 26 20:03 test.html
[root@VM-0-10-centos html]# pwd
/soft/data/docker/html
进入容器查看:
[root@VM-0-10-centos html]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e0c7ed8c9999 nginx "/docker-entrypoint.…" 46 minutes ago Up 46 minutes 0.0.0.0:49160->80/tcp, :::49160->80/tcp nginx
进入容器后可以查看到刚刚在主机上创建的html文件,在容器相应的路径上也存在。
[root@VM-0-10-centos html]# docker exec -it nginx /bin/bash
## 可以看到/soft/nginx/html
root@e0c7ed8c9999:/# cd /soft/nginx/html
root@e0c7ed8c9999:/soft/nginx/html# ls -lsa
total 12
4 drwxr-xr-x 2 root root 4096 Dec 26 12:03 .
4 drwxr-xr-x 3 root root 4096 Dec 26 11:19 ..
4 -rw-r--r-- 1 root root 555 Dec 26 12:03 test.html
将刚刚创建的test.html复制到 /usr/share/nginx/html/ 下
root@e0c7ed8c9999:/soft/nginx/html# cp test.html /usr/share/nginx/html/
然后在浏览器进行访问如下所示:
上面挂载容器卷的命令是 -v,也可以使用 –mount命令:
[root@VM-0-10-centos ~]# docker run -d --name my-nginx -P --mount type=bind,source=/soft/data/docker/my-nginx,destination=/soft/container/nginx nginx
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /soft/data/docker/my-nginx.
See 'docker run --help'.
需要注意的是宿主机挂载的路径必须存在否则会报错如上所示:
[root@VM-0-10-centos ~]# mkdir -p /soft/data/docker/my-nginx
[root@VM-0-10-centos ~]# docker run -d --name my-nginx -P --mount type=bind,source=/soft/data/docker/my-nginx,destination=/soft/container/nginx nginx
bdf701f0a0835089e408d750381684f74ab8393f708cfc0678c4b6b3e21e5254
登录nginx容器查看路径映射是否存在。
[root@VM-0-10-centos ~]# docker exec -it my-nginx /bin/bash
root@bdf701f0a083:/# cd /soft/container/nginx/
root@bdf701f0a083:/soft/container/nginx# ls -lsa
total 8
4 drwxr-xr-x 2 root root 4096 Dec 26 14:23 .
4 drwxr-xr-x 3 root root 4096 Dec 26 14:23 ..
容器内创建文档:
root@bdf701f0a083:/soft/container/nginx# echo "test message" > haha.txt
root@bdf701f0a083:/soft/container/nginx# ls -lsa
total 12
4 drwxr-xr-x 2 root root 4096 Dec 26 14:29 .
4 drwxr-xr-x 3 root root 4096 Dec 26 14:23 ..
4 -rw-r--r-- 1 root root 13 Dec 26 14:29 haha.txt
宿主机查看文本内容:
[root@VM-0-10-centos ~]# cat /soft/data/docker/my-nginx/haha.txt
test message
需要注意的是宿主机的路径必须为绝对路径,使用-- mount
需要确定挂载的路径存在否则会出错,Docker在挂载主机目录的时候也可以指定目录的读写权限,默认权限是读写(rw),用户也可以指定只读权限即 ro:
docker run -d --name my-nginx -P --mount type=bind,source=/soft/data/docker/my-nginx:ro,destination=/soft/container/nginx nginx
加了 ro权限后,容器只能对挂载的路径进行进行读取,无法修改数据卷内的数据。
创建共享数据卷容器
一般在开发中往往会遇到多个容器直接共享同一批数据,可以使用 数据卷容器,需要注意的是数据卷容器本身也是一个容器 ,下面以三个centos镜像为例演示容器数据卷的使用:
- 下载centos镜像:
[root@VM-0-10-centos ~]# docker pull centos:7
7: Pulling from library/centos
2d473b07cdd5: Pull complete
Digest: sha256:9d4bcbbb213dfd745b58be38b13b996ebb5ac315fe75711bd618426a630e0987
Status: Downloaded newer image for centos:7
docker.io/library/centos:7
创建一个数据卷容器
[root@VM-0-10-centos ~]# docker run -it -v /dir --name dir centos:7
在 dir目录中新建一个文件并输入内容:
[root@8d3d2d3d6edf /]# echo "Hi I am GalenGao" > /dir/test.txt
使用 crtl + p + q 退出容器,然后在新启动两个容器centos1、centos2挂载容器卷。
创建容器centos1中查看是否存在对应的容器卷目录:
[root@VM-0-10-centos volumes]# docker run -it --name centos1 --volumes-from dir centos:7
可以清晰看到对应的 dir目录存在且test.txt文档也存在,这个时候我们追加一些文本内容:
[root@6cc32c0aeb05 dir]# echo "it's a message from centos1" >> test.txt
创建容器centos2中查看对应的文本内容:
[root@VM-0-10-centos volumes]# docker run -it --name centos2 --volumes-from dir centos:7
[root@a1db0373c9c8 /]# cat /dir/test.txt
Hi I am GalenGao
it's a message from centos1
从上面的演示可以看出centos1与centos2容器对同一个目录下文件输出,均可在彼此对应的目录查看,这就达到数据共享的目的了。
删除共享数据卷
运行中的容器进行了删除,并不会影响其真实宿主机相应的内容,如果要删除容器的时候需要同时删除其数据卷,需要在最后一个挂载真实宿主机的容器中指定相应的容器数据卷,例如删除刚刚创建的容器数据卷就可以使用 docker rm -v 命令来指定同时删除关联的容器。
[root@VM-0-10-centos volumes]# docker rm -f dir -v /dir
/dir
Error response from daemon: removal of container dir is already in progress
[root@VM-0-10-centos volumes]# docker ps