存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。这就意味着,当我们在容器中的这个目录下写入数据时,容器会将其内容直接写入到宿主机上与此容器建立了绑定关系的目录。
宿主机的/data/web 目录与容器中的/container/data/web 目录绑定关系,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器直接访问宿主机中的内容,也可以宿主机向容器写入内容, 容器和宿主机的数据读写是同步的。
数据丢失问题
容器按照业务类型,总体可以分为两类:
实际业务总是有各种需要数据持久化的场景,比如 MySQL、 Kafka 等有状态的业务。因此为了解决有状态业务的需求, Docker 提出了卷(Volume)的概念。
性能问题
UnionFS 对于修改删除等,一般效率非常低,如果对一于 I/O 要求比较高的应用,如redis 在实现持化存储时,是在底层存储时的性能要求比较高 。
宿主机和容器互访不方便
宿主机访问容器,或者容器访问要通过 docker cp 来完成,应用很难操作。
目前docker提供了三种方式将数据从宿主机挂载到容器中
volume docker管理卷
volume docker 管理卷,默认映射到宿主机的/var/lib/docker/volumes 目录下, 只需要在容器内指定容器的挂载点是什么。
而被绑定宿主机下的那个目录,是由容器引擎 daemon 自行创建一个空的目录,或者使用一个已经存在的目录,与存储卷建立存储关系。
这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定那些使用目录,临时存储比较适合;
bind mount绑定数据卷
bind mount 绑定数据卷,映射到宿主机指定路径下,在宿主机上的路径要人工的指定一个特定的路径, 在容器中也需要指定一个特定的路径, 两个已知的路径建立关联关系。
tmpfs mount临时数据卷
tmpfs mount 临时数据卷,映射到于宿主机内存中,一旦容器停止运行, tmpfsmounts 会被移除,数据就会丢失,用于高性能的临时数据存储。
创建卷:存储卷可以通过命令方式创建,也可以在创建容器的时候通过 -v and --mount 指定。
基本命令
命令 | 别名 | 功能 | 备注 |
---|---|---|---|
docker volume create | 创建存储卷 | ||
docker volume inspect | 显示存储卷详细信息 | ||
docker volume ls | docker volume list | 列出存储卷 | |
docker volume prune | 清理所有无用数据卷 | ||
docker volume rm | 删除卷,使用中的无法 删除 |
功能:创建存储卷
语法:
docker volume create [OPTIONS] [VOLUME]
关键参数:
创建一个匿名卷
创建一个命名卷
增加标签信息:日期date
功能:查看卷详细信息
语法:
docker volume inspect [OPTIONS] VOLUME [VOLUME...]
功能:列出卷
语法:
docker volume ls [OPTIONS]
关键参数:
功能:删除卷,需要容器没有使用该卷
语法:
docker volume rm [OPTIONS] VOLUME [VOLUME...]
关键参数:
功能:删除不使用的本地卷
语法:
docker volume prune [OPTIONS]
关键参数:
-v 和-mount 都可以完成管理卷的创建
• 功能:完成目录映射
• 语法
Shell
docker run -v name:directory[:options] .........
参数
○ 第一个参数:卷名称
○ 第二个参数:卷映射到容器的目录
○ 第三个参数:选项,如 ro 表示 readonly
案例
docker images
docker run -d --name myvolnginx2 -v volnginx2:/usr/share/nginx/html/ nginx:1.21.1 # 创建一个存储卷,并映射到容器myvolnginx2的/usr/share/nginx/html目录下
docker ps
docker volume ls
接下来我们查看volume对应目录下的内容
docker volume inspect volnginx2
ls -l /var/lib/docker/volumes/volnginx2/_data
下面我们进入到容器中,并删除对应目录下的文件。如何查看存储卷对应目录下的内容:
docker exec -it myvolnginx2 bash
cd /usr/share/nginx/html
ls
rm -r *.html
ls
exit
ls -l /var/lib/docker/volumes/volnginx2/_data
存储卷目录下的文件被成功删除,说明容器中的目录成功和宿主机目录关联在一起。
功能:完成目录映射
语法:
--mount '=,='
关键参数
样例
docker images nginx
docker run -d --name myvolnginx3 --mount 'src=volnginx3,dst=/usr/share/nginx/hmtl' nginx:1.21.1
docker ps
docker volume inspect volnginx3
ls -l /var/lib/docker/volumes/volnginx3/_data
bind mount 绑定数据卷,映射到宿主机指定路径下,在宿主机上的路径要人工的指定一个特定的路径, 在容器中也需要指定一个特定的路径, 两个已知的路径建立关联关系。
功能:完成卷映射
• 语法
docker run -v name:directory[:options] .........
参数
○ 第一个参数: 宿主机目录,这个和管理卷是不一样的;如果是存储卷的名字创建的就是管理卷,如果是存储卷的目录,创建的就是存储卷
○ 第二个参数:卷映射到容器的目录
○ 第三个参数:选项,如 ro 表示 readonly
案例:
docker run -d --name 容器的名字 -v 宿主机目录:容器的目录 镜像id/镜像名称
docker exec -it 容器的名字 bash
功能:完成目录映射
• 语法
--mount '=,='
关键参数
○ type : 类型表示 bind, volume, or tmpfs
○ source , src : 宿主机目录,这个和管理卷是不一样的。
○ destination, dst,target:文件或目录挂载在容器中的路径
○ ro,readonly: 只读方式挂载
案例
docker run -d --name 容器名 --mount type=bind,src=宿主机目录,target=容器目录 镜像id/镜像名称
docker exec -it 容器的名字 bash
tmpfs mount 临时数据卷,映射到于宿主机内存中,一旦容器停止运行, tmpfs mounts 会被移除,数据就会丢失,用于高性能的临时数据存储。
tmpfs 局限性:
功能:完成临时卷映射
语法:
--tmpfs /app
案例
docker run -d --name 容器名 --tmpfs 容器目录
一旦容器重新启动,临时卷的数据就会丢失。
功能:完成目录映射
语法:
--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 容器名 --mount type=tmpfs dst=容器目录 镜像名
实验结论:普通容器是在可写层写入文件,而tmpfs的内容不是存储在容器的可写层里面
步骤一:创建一个普通容器,写入文件,并在宿主机上面查找文件
docker run -d --name tmptest1 nginx:1.21.1
docker ps
# 进入容器
docker exec -it tmptest1 bash
mkdir -p /app
echo 1 > /app/mylabel.txt
exit
find / -name mylabel.txt
我们在宿主机上查找文件,文件被找到了,是因为他在容器的可写层
步骤二:创建一个临时卷,写入文件,并在宿主机上查找文件
docker run -d --name tmptest2 --tmpfs /app nginx:1.21.1
docker ps
# 进入容器
docker exec -it tmptest2 bash
echo 222 > /app/mynewlabel.txt
exit
# 在宿主机上面查找文件
find / -name mynewlabel.txt
所以 tmpfs 的内容不是存储在我们的容器的可写层里面的。
使用 MySQL 5.7 的镜像创建容器并创建一个普通数据卷 mysql-data 用来保存容器中产生的数据。需要在容器中连接 MySQL 服务, 并创建数据库 test, 并在在该数据库中创建一个简单的表并插入一些数据进来。
步骤一:创建数据库容器,并登入数据库
docker run -d --name mysql-demo -e MYSQL_ROOT_PASSWORD=root -p 8200:3306 -v /home/west/myworkdir/mysqldata:/var/lib/mysql mysql:5.7
docker exec -it mysql-demo bash
mysql -u root -p
#这里输入的密码,就是MYSQL_ROOT_PASSWORD后面的值
-e 选项通过参数 MYSQL_ROOT_PASSWORD 来传递 MySQL 密码
查看挂载信息:
docker container inspect mysql-demo | grep "Mounts" -A 10
步骤二:向数据库中插入数据
create database user;
use user;
create table student(sno char(3), sname varchar(10));
insert into student values('1', 'zs'),('2', 'ls');
select * from student;
在宿主机上面查看volume:
ls -l /home/west/myworkdir/mysqldata
可以看到容器中 MySQL 创建的数据库和表数据以及持久化到宿主机挂载的目录下了
第三步:MYSQL灾难恢复
有一天莫名其妙停电了, 然后服务器重启了,这个时候 Mysql 没有起来;由于磁盘空间不够,把所有停止的容器都删除了。结果我们的 Mysql容器也没有了 ,我们的数据也丢失了。
docker ps
docker stop mysql-demo
docker rm mysql-demo
如何恢复数据?只需要重新启动容器,并挂载相应的管理卷
docker run -d --name mysql-demo -e MYSQL_ROOT_PASSWORD=root -p 8200:3306 -v /home/west/myworkdir/mysqldata:/var/lib/mysql mysql:5.7
# 连接数据库并查看数据是否恢复
docker exec -it mysql-demo bash
mysql -u root -p
可以看到数据成功恢复