docker的数据卷、docker数据持久化

目录

前言

环境:centos7.9 docker version 20.10.14

本篇我们来介绍docker的数据卷,数据卷是用于实现docker数据的持久化。

docker数据持久化的2种方式

使用docker过程中,我们需要持久化容器中产生的数据,以及容器与容器之间、容器与主机之前进行数据共享、备份等操作,这里就需要到容器的数据持久化管理。 docker的数据持久化管理目前提供如下两种方式:

bash 复制代码
1、数据卷 data volumes
2、数据卷容器 data volumes containers

数据卷 bind mount ,即-v参数

数据卷:数据卷其实就是一个目录或文件,类似linux下对目录或文件进行mount挂载操作,即在宿主机和容器之间建立一个或多个目录(文件亦可)来相互映射文件,其具有如下特点:

(1) 数据卷可以在容器之间进行共享和重用,即多个容器可以挂载同一个目录

(2)对数据卷的更改会立即生效,即对宿主机目录下的文件的修改会立即反应到容器的挂载点目录文件

(3)对数据卷的更新不会影响到镜像 (镜像只读)

(4)卷会一直存在,即使容器被删除,即宿主机目录不会因为容器的删除而删除宿主机目录

注意:

(1)删除容器的时候,数据卷不会删除。如果要删除容器的时候同时删除数据卷,需加上-v参数。比如: docker rm os456 -v /homedata

(2)默认数据卷挂载以后文件的权限为rw,如需单独设置,可以容器数据卷后边设置:ro只读

docker run -v参数语法:

bash 复制代码
-v <host_path>:<container_path>[:rw/ro]
<host_path>是宿主机的目录或单个文件
<container_path>是容器的目录或单个文件
rw/ro 表示挂载后容器的数据读写权限,rw表示读写,ro表示数据只读,不写默认就是rw读写权限

演示示例:

bash 复制代码
#使用数据卷挂载宿主机目录到容器中去
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"
            }
        ],

匿名数据卷 docker manager volume

使用-v参数时可以不指定<host_path>部分,只需指定容器的挂载点即可,如:-v <container_path> ,container_path必须是一个容器目录,不能是单个文件了,数据权限不能设置,均为读写权限。这时docker会自动创建一个匿名的数据卷,这个匿名数据卷的名字是自动生成的一个很长串的字符。使用docker volume ls命令可以看到这个数据卷的名称,我们称这种卷为匿名数据卷。

演示示例:

bash 复制代码
使用-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页面的变更

-v参数和匿名卷的区别

不同点 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参数时不指定<host_path>部分,只需指定容器的挂载点即可,如:-v <container_path> ,这是docker默认会创建目录,如/var/lib/docker/volumes/8d1d766c65d3b3cddafd20f25dcaf304a96b9c89d005d30226a7b815a6b5ecbf/_data/目录,这个目录就是容器持久化数据的目录,这一串很长的ID就是卷名,docker自动帮我们生成的,通过docker volume ls命令可以查看卷。

注意:

使用数据卷 bind mount ,即-v参数,挂载后容器内的挂载点目录会被覆盖,如果此时宿主机目录上没有文件,那么容器的挂载点也没有文件;

使用匿名数据卷时,如果volume是空的而container中的目录有内容,那么docker会将container目录中的内容拷贝到volume中,但是如果volume中已经有内容,则会将container中的目录覆盖。

docker volume 命令的使用

bash 复制代码
[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参数挂载同一个宿主机目录即可,如下实现:

bash 复制代码
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、使用数据卷容器之后,多个容器共享相同的数据,如下实现:

bash 复制代码
#创建一个数据卷容器,名称叫做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。

删除volume:

1、对于直接使用-v /root/nginx/html/:/usr/share/nginx/html指定宿主机目录挂载的,当删除容器时,宿主机上的目录并不会被删除,这也是数据持久化的含义,所以如果需要永久删除宿主机目录,可以在确认数据不再需要后删除宿主机目录即可。

2、对于使用docker manager volume管理的,如果是匿名卷,在删除容器的时候加上-v可以直接删除容器和匿名卷,docker rm命令如下:

bash 复制代码
[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容器实现数据持久化一般有以下几种方式:

bash 复制代码
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"
            }
        ],
bash 复制代码
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 ~]# 
bash 复制代码
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、数据卷容器

bash 复制代码
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、孤儿卷

bash 复制代码
所谓孤儿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 
相关推荐
景天科技苑2 小时前
【云原生开发】K8S多集群资源管理平台架构设计
云原生·容器·kubernetes·k8s·云原生开发·k8s管理系统
wclass-zhengge3 小时前
K8S篇(基本介绍)
云原生·容器·kubernetes
颜淡慕潇3 小时前
【K8S问题系列 |1 】Kubernetes 中 NodePort 类型的 Service 无法访问【已解决】
后端·云原生·容器·kubernetes·问题解决
川石课堂软件测试5 小时前
性能测试|docker容器下搭建JMeter+Grafana+Influxdb监控可视化平台
运维·javascript·深度学习·jmeter·docker·容器·grafana
昌sit!11 小时前
K8S node节点没有相应的pod镜像运行故障处理办法
云原生·容器·kubernetes
追风林12 小时前
mac 本地docker-mysql主从复制部署
mysql·macos·docker
A ?Charis14 小时前
Gitlab-runner running on Kubernetes - hostAliases
容器·kubernetes·gitlab
城南vision14 小时前
Docker学习—Docker核心概念总结
java·学习·docker
wclass-zhengge14 小时前
Docker篇(Docker Compose)
运维·docker·容器
北漂IT民工_程序员_ZG15 小时前
k8s集群安装(minikube)
云原生·容器·kubernetes