存储卷
存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上 的某一目录建立绑定关系。这就意味着,当我们在容器中的这个目录下写入数据时, 容器会将其内容直接写入到宿主机上与此容器建立了绑定关系的目录。
在宿主机上的这个与容器形成绑定关系的目录被称作存储卷。卷的本质是文件或者目 录,它可以绕过默认的联合文件系统,直接以文件或目录的形式存在于宿主机上。
宿主机的/data/web 目录与容器中的/container/data/web 目录绑定关系,然后容器中的 进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿 主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器 直接访问宿主机中的内容,也可以宿主机向容器写入内容,容器和宿主机的数据读写是同步的。
存储卷作用
1、数据丢失问题
显然,容器更擅长无状态应用。因为未持久化数据的容器根目录的生命周期与容器的 生命周期一样,容器文件系统的本质是在镜像层上面创建的读写层,运行中的容器对 任何文件的修改都存在于该读写层,当容器被删除时,容器中的读写层也会随之消失。
虽然容器希望所有的业务都尽量保持无状态,这样容器就可以开箱即用,并且可以任 意调度,但实际业务总是有各种需要数据持久化的场景,比如 MySQL、Kafka 等有状 态的业务。因此为了解决有状态业务的需求,Docker 提出了卷(Volume)的概念。
2、性能问题
联合文件系统 对于修改删除等,一般效率非常低,如果对一于 I/O 要求比较高的应用,如 redis 在实现持化存储时,是在底层存储时的性能要求比较高。
3、宿主机和容器互访不方便
宿主机访问容器,或者容器访问要通过 docker cp 来完成,应用很难操作
4、容器和容器共享不方便
存储卷分类
Docker 提供了三种方式将数据从宿主机挂载到容器中
• volume docker 管理卷,默认映射到宿主机的/var/lib/docker/volumes 目录 下,只需要在容器内指定容器的挂载点是什么,而被绑定宿主机下的那个目录,是由容器引擎daemon****自行创建一个空的目录,或者使用一个已经存在的目录,与存储卷 建立存储关系,这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定 那些使用目录,临时存储比较适合;
• bind mount 绑定数据卷,映射到宿主机指定路径下,在宿主机上的路径要人工的 指定一个特定的路径,在容器中也需要指定一个特定的路径,两个已知的路径建立关****联关系
• tmpfs mount 临时数据卷,映射到于宿主机内存中,一旦容器停止运行,tmpfs mounts 会被移除,数据就会丢失,用于高性能的临时数据存储。
管理卷
创建卷
方式1 Volume****命令操作
|-----------------------|--------------------|---------------|
| 命令 | 别名 | 功能 |
| docker volume create | | 创建存储卷 |
| docker volume inspect | | 显示存储卷详细信息 |
| docker volume ls | docker volume list | 列出存储卷 |
| docker volume prune | | 清理所有无用数据卷 |
| docker volume rm | | 删除卷,使用中的无法 删除 |
docker volume create命令
功能
创建存储卷
语法
docker volume create [OPTIONS] [VOLUME]
关键参数
-d, --driver**:**指定驱动,默认是 local
--label**:**指定元数据
1、创建一个匿名卷

2、创建命名卷

3、--lable参数
指定元数据

docker volume inspect命令
功能
查看卷详细信息
语法
docker volume inspect [OPTIONS] VOLUME [VOLUME...]
关键参数
-f**:**指定相应个格式,如 json

docker volume ls命令
功能
列出卷
语法
docker volume ls [OPTIONS]
关键参数
--format**:**指定相应个格式,如 json,table
**--filter,-f:**过滤
**-q:**仅显示名称

-f参数
过滤

-q参数
仅显示名称

docker volume rm命令
功能
删除卷,需要容器不使用。
语法
docker volume rm [OPTIONS] VOLUME [VOLUME...]
关键参数
**-f,--force:**强制删除

docker volume rm删除卷,如果里面有数据也会清理掉。
docker volume prune命令
功能
删除不使用的本地卷
语法
docker volume prune [OPTIONS]
关键参数
**--filter:**过滤
-f, --force:不提示是否删除

docker volume prune 删除不使用的本地卷,会对匿名卷进行清理,对于命名卷则不会进行清理
方式2 -v或者--mount****指定
-v 和-mount 都可以完成管理卷的创建
-v参数
功能
完成目录映射
语法
docker run -v name:directory[:options] .........
参数
第一个参数:卷名称
第二个参数:卷映射到容器的目录
第三个参数:选项,如 ro 表示 readonly
创建容器,执行命令 docker run -d --name myvoluenginx01 -v volnginx1:/usr/share/nginx/html/ nginx:1.23.4
这句命令是运行nginx容器,后台运行,命名为myvoluenginx01,指定管理卷名称为volnginx1,映射到容器的目录为/usr/share/nginx/html/

可以看到,如果容器映射目录下有文件,会将容器目录下的文件拷贝至宿主机的映射的目录
如果使用ro参数,即运行命令 docker run -d --name myvoluenginx01 -v volnginx1:/usr/share/nginx/html/:ro nginx:1.23.4
则不能删除宿主机和容器映射的目录了
--mount参数
功能
完成目录映射
语法
--mount '<key>=<value>,<key>=<value>'
关键参数
type: 类型表示 bind, volume, or tmpfs
source**,**src:对于命名卷,这是卷的名称。对于匿名卷,省略此字段。
destination**,**dst,target:文件或目录挂载在容器中的路径
**ro,readonly:**只读方式挂载
创建容器(命名卷),执行命令 docker run -d --name myvoluenginx02 --mount 'src=volnginx2,dst=/usr/share/nginx/html' nginx:1.23.4

创建容器(匿名卷),执行命令 docker run -d --name myvoluenginx03 --mount 'dst=/usr/share/nginx/html' nginx:1.23.4
这样创建的容器是匿名卷
这样创建的匿名卷名称如何查看呢?
通过查看容器详细信息可以找到

通过刚刚查到的匿名卷查看卷的摘要信息和详情

方式3 Dockerfile****匿名卷
操作
docker命令创建卷管理卷
1、创建管理卷
docker volume create test1
查看卷映射路径下有没有文件

2、创建一个容器,并和创建的卷进行绑定
docker run -d --name nginx1 -p 8081:80 nginx:1.23.4 -v test1:/usr/share/nginx/html
3、再次查看卷映射路径下有没有文件

可以看到卷映射路径下有了文件,是因为容器和宿主机建立了绑定目录关系之后,文件是共享的,存在的文件会主动共享到不存在的一方
4、查看容器的详细信息

5、在宿主机的映射目录下对主页进行修改

然后在web端访问主页

进入容器,查看nginx主页文件内容,也能看见同步的修改

docker -v创建管理卷
1、-v创建管理卷(可读),并启动容器
执行命令 docker run -d --name nginx2 -p 8082:80 -v test2:/usr/share/nginx/html/:ro nginx:1.23.4

2、进入容器,对映射关系的目录下的主页进行修改

3、退出容器,在宿主机上对映射关系的目录下的主页进行修改

在web端访问nginx主页查看

再次进入容器,进行检查

可以看到也同步修改了
可以看到ro只保护了容器内部,但是在宿主机上并不生效。
docker --mount创建管理卷
1、--mount创建容器,并启动容器
执行命令 docker run -d --name nginx3 -p 8085:80 --mount 'src=test3,dst=/usr/share/nginx/html' nginx:1.23.4
2、查看映射关系目录下的文件

3、宿主机上修改映射关系目录下的首页文件

4、进入容器,进行检查

可以看到发生了同步变化,在web端访问主页

docker卷生命周期
1、-v创建管理卷,并启动容器
执行命令 docker run -d -v test4:/usr/share/nginx/html --name nginx4 -p 8086:80 nginx:1.23.4
2、查看映射关系目录下的文件

2、关掉容器,并删除

3、查看宿主机刚刚映射关系目录下的文件是否还在

依旧还在
4、通过docker volume rm 删除卷,然后再来查看目录下的文件

docker卷的生命周期就是,一旦创建了这个卷,容器的删除并不会影响卷里面的内容。但是通过docker volume rm 删除卷,就能清理掉卷
docker卷共享
1、-v 创建管理卷,并且启动 2 容器,指定同一个卷
执行命令 docker run -d --name nginx4 -v test4:/usr/share/nginx/html -p 8086:80 nginx:1.23.4
docker run -d --name nginx5 -v test4:/usr/share/nginx/html -p 8087:80 nginx:1.23.4

2、查看卷在宿主机上映射的目录

再一次访问两个容器的nginx主页


3、在宿主机上对映射目录下的主页文件进行修改

然后再访问两个容器的nginx主页


docker卷的共享,可以将多个容器绑定到一个卷上,实现一处修改多处同步更新
绑定卷
创建卷
-v****参数创建卷
功能
完成卷映射
语法
docker run -v name:directory[:options] .........
参数
第一个参数:宿主机目录,这个和管理卷是不一样的(指定为宿主机的目录,就是创建的绑定卷。如果不指定,就是创建的匿名管理卷,指定名称,就是创建命名管理卷)
第二个参数:卷映射到容器的目录
第三个参数:选项,如 ro 表示 readonly
新建目录bindDir作为宿主机绑定的目录并进入,然后创建容器并绑定宿主机新建的目录
执行命令 docker run -d --name nginx1 -v /root/bindDir:/usr/share/nginx/html nginx:1.23.4
通过查看容器的详情里的Mounts字段查看绑定情况。
执行命令 docker container inspect nginx1

查看宿主机目录下的文件,是否和容器绑定卷下文件同步

文件为空
宿主机在绑定卷位置创建文件

进入容器,在绑定卷位置查看文件

宿主机管理卷位置文件发生变化,在容器中管理卷位置文件也会同步发生变化。
另外如果宿主机目录为空,容器不为空,则容器目录也会被清空。也就是以宿主机管理卷位置为准。
--mount****参数创建绑定卷
功能
完成目录映射
语法
--mount '<key>=<value>,<key>=<value>'
参数
type: 类型表示 bind, volume, or tmpfs
source**,**src:宿主机目录,这个和管理卷是不一样的。
destination**,**dst,target:文件或目录挂载在容器中的路径
**ro,readonly:**只读方式挂载
创建容器,执行命令 docker run -d --name nginx2 --mount type=bind,src=/root/bindDir,dst=/usr/share/nginx/html nginx:1.23.4
如果type参数不指定,则会被认为是管理卷。
查看容器和宿主机绑定卷关系

查看宿主机下目录文件内容

进入容器,对绑定卷下的文件进行确认和修改。

然后退出容器进行查看

操作
mount****创建绑定卷
运行容器,指定宿主机目录不存在的绑定卷
执行命令 docker run -d --name nginx3 --mount type=bind,src=dataX,dst=/usr/share/nginx/html nginx:1.22.0

创建失败。
将bindDir下的test.txt改为index.html文件

然后创建容器,绑定绑定卷位置。
执行命令 docker run -d --name nginx3 --mount type=bind,src=/root/bindDir,dst=/usr/share/nginx/html nginx:1.22.0
查看绑定卷映射关系。

分别检查宿主机和容器内目录文件内容

如果宿主机绑定卷位置不存在,则容器无法启动。
如果宿主机和容器绑定卷位置都存在,以宿主机绑定卷位置为准。
-v****创建绑定卷
运行容器,指定宿主机目录不存在的绑定卷
执行命令 docker run -d --name nginx4 -v /root/DataXX:/usr/share/nginx/html nginx:1.23.4

不存在的目录自动创建
运行容器,指定宿主机目录存在的绑定卷

如果宿主机绑定卷位置不存在,容器能启动,并且自动创建宿主机绑定卷目录。
如果宿主机和容器绑定卷位置都存在,以宿主机绑定卷位置为准。
绑定卷共享
1、启动两个绑定卷,都绑定到宿主机的同一个目录
执行命令 docker run -d --name nginx6 -v /root/bindDir:/usr/share/nginx/html -p 8081:80 nginx:1.23.4
docker run -d --name nginx7 -v /root/bindDir:/usr/share/nginx/html -p 8082:80 nginx:1.23.4
查看宿主机绑定卷内容

分别访问两个容器的nginx主页


2、修改宿主机绑定卷位置文件内容

3、访问web端nginx主页


绑定卷共享和管理卷共享是是类似的,都是实现一处修改多处同步更新
临时卷 tmpfs
临时卷数据位于宿主机内存中,在容器和宿主机之外。
局限性
不同于卷和绑定挂载,不能在容器之间共享 tmpfs 挂载。
这个功能只有在 Linux 上运行 Docker 时才可用。
创建卷
方式1 指定**--tmpfs****创建**
功能
完成临时卷映射
语法
--tmpfs /app
创建容器,执行命令 docker run -d --name nginx8 --tmpfs /test1 nginx:1.23.4
查看容器详情,执行命令 docker container inspect nginx8
在HostConfig字段下可以看到

进入容器中的临时卷目录,创建文件

然后对容器重启,在进入到临时卷目录下查看文件

创建的临时卷存在宿主机内存中,一旦容器重启或者停止,数据就会消失
方式2 --mount****指定参数创建
功能
完成目录映射
语法
--mount '<key>=<value>,<key>=<value>'
参数
type: 类型表示 bind, volume, or tmpfs
destination**,**dst,target:挂载在容器中的路径
tmpfs-size**:**tmpfs 挂载的大小(以字节为单位)。默认无限制。
tmpfs-mode**:**tmpfs 的八进制文件模式。例如,700 或 0770。默认为 1777 或全局可写。
创建容器,执行命令 docker run -d --name nginx9 --mount type=tmpfs,dst=/test2 nginx:1.23.4
查看容器详情

进入容器中的临时卷目录,创建文件

然后对容器重启,在进入到临时卷目录下查看文件

一旦容器停止或重启,临时卷的数据就没有了
操作
tmpfs****参数创建临时卷
1、创建临时卷并绑定到nginx主页目录,并启动容器
执行命令 docker run -d --name nginx1 --tmpfs /usr/share/nginx/html -p 8081:80 nginx:1.23.4
2、进入容器,查看首页内容是否存在。如果没有,就创建一个 首页

3、web端访问nginx主页

如果对容器重启,临时卷的文件就没了
如果临时卷刚好绑定到了nginx首页所在目录,临时卷会把里面的内容覆盖掉。
虽然临时卷在内存里,但是nginx看到的还是这个文件,所以还是能正常工作。
mount****创建临时卷
1、创建临时卷绑定nginx主页目录,并限制临时卷大小,并启动容器
执行命令 docker run -d --name nginx2 --mount type=tmpfs,dst=/usr/share/nginx/html,tmpfs-size=1m -p 8082:80 nginx:1.23.4
2、进入容器,观察nginx主页目录。如果没有主页文件,就进行创建

在web端访问

3、向容器内的nginx主页目录放入一个大于规定大小的文件
首先向容器内部拷入一个大于规定大小的文件,我是拷到容器的根目录下的

然后在容器内部进行查看和文件拷贝

mount创建临时卷也会将容器中临时卷位置进行覆盖。
在nginx内存中创建的文件,对于nginx来说没有感知,都是一个文件。
如果临时卷目录放入一个比限制大小大的文件,是不能成功的
tmpfs****失踪了
1、创建普通容器,不绑定临时卷。并在容器内写入一个文件
创建容器,执行命令 docker run -d --name nginx3 nginx:1.23.4
在容器内部创建文件

2、在宿主机上看看找不找的到这个文件

找到了,和刚刚写入的文件内容也是一样的。
其实对文件的操作都会反应到宿主机上,而且在宿主机上是可以看到文件的内容。
存在安全性问题
1、创建普通容器,绑定临时卷。并在容器内的临时卷目录写入一个文件
docker run -d --name nginx4 --mount type=tmpfs,dst=/test nginx:1.23.4
在容器临时卷目录下创建文件

2、在宿主机上看看找不找的到这个文件

找不到的
临时卷是放在宿主机的内存上的,再宿主机上是看不到临时卷的文件和内容的。
也反映了临时卷的安全性
MySQL灾难恢复
1、绑定卷,并创建容器
执行命令 docker run --name mysql -v /mysqlData:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=704756098 -d mysql:5.7

可以看到mysql数据内容都放到了宿主机卷目录下了
2、进入mysql容器,进行数据业务操作。建数据库、建表、新增数据
进入数据库

建数据库

建表

新增数据,然后查询

3、删除mysql容器

4、再启动一个新的mysql容器,并绑定之前的绑定卷上
执行命令 docker run --name mysqlNew -v /mysqlData:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=704756098 -d mysql:5.7
5、进入新的mysql容器,检查数据还在不在
进入容器

检查数据库

检查表

查询表数据

常见问题
什么时候用 Volume,什么时候用 bind、tmpfs?
volume:volume 是 docker 的宿主机文件系统一部分,用于不需要规划具体目录的场 景
bind:bind mount 完全是依赖于主机的目录结构和操作系统,用于目录需要提前规划, 比如 mysql 的目录需要个空间大的,其他服务有不占用的时候,用 volume 就不太合 适了
tmpfs:用于敏感文件存储,文件不想存储的宿主机和容器的可写层之中