【docker】存储卷
什么是存储卷:宿主机和容器的目录绑定关系,然后容器中的进程向这个目录写数据时,就是直接写在宿主机目录上。反之亦然。两者的数据读写一致。
应用
数据持久化
如果容器对相关数据删除,宿主机还会保存这一部分数据。
性能问题
UnionFS对于修改和删除效率太低了,需要一层一层寻找到宿主机。如果使用存储卷,就可以直接找到宿主机
容器和宿主机方便共享
原本需要docker cp完成容器和宿主机cp,现在只需要创建存储卷就可以了。而且,对于容器和容器,想要完成共享会更复杂,使用存储卷就可以最简单完成共享了。
分类
type of mount 文件挂载类型
volume docker 管理卷
管理卷 :宿主机的目录由docker管理,目录默认放在/var/lib/docker/volumes目录下
优点:docker管理,方便
不精准:docker管理不能准确指定使用哪些目录,常作为临时存储
bind mount 绑定卷
绑定卷:宿主机的路径由用户设置、而不是由docekr默认创建
缺点和优点:与 volume docker 正好相反,如果这个目录有东西,我们需要判断是否是容器需要的,如果不需要,要挪出去。实际生产中bind mount使用的最频繁了。
tmpfs mount 临时数据卷
临时卷:容器的目录绑定到宿主机的内存
优点:安全、快速,放内存上不容易被看到
缺点:容器一丢失数据,数据就丢失了,不能持久化
命令
管理卷 volume
用的少,了解
docker volume create 创建存储卷
shell
docker volume create [OPTIONS] [VOLUME]
# -d 指定驱动
# --label 指定元数据,也就是指定描述的创建卷的描述信息
示例:
shell
docker volume create # 创建匿名卷,此时会回显卷的默认名称
docker volume ls # 查看卷
docker volume inspect + 卷id # 查看详细信息,可以看到/data/var/lib/docker/volumes/卷名称/_data我们使用ll查看对应目录,发现默认是空的
docker volume create myvolume # 创建命名卷,回显myvolume,表示卷的名称
docker volume --laber MYTEST=1 myvolume2 # 可以在Labels字段发现MYTEST
docker volume inspect
docker volume ls
参数:
shell
-- format可以指定输出格式
-f 可以完成过滤
-q 只返回名字
docker volume prune 删除没有使用的匿名卷(对命名卷不处理)
docker volume rm 删除卷
shell
docker rm -f test-container # 解除卷与容器的关联,不然没法直接删除管理卷
docker volume rm test-vol # 删除卷
如果卷里面有数据也会清理掉,会连带关联的目录一起清理掉
要区分卷和容器的区别,卷本质上就是在宿主机创建了保存容器数据、完成交互的桥梁,如果仅仅删除容器,不会导致管理卷丢失,也就不会导致宿主机存储的容器的数据丢失,但是如果删除管理卷,数据就真的丢失了
-v 指明目录并创建管理卷
shell
docker run -d --name myvolnginx1 -v volnginx1:/usr/share/nginx/html/ nginx:1.24.0
docker volume ls # 可以查看到刚刚设置的管理卷了
ll /data/var/lib/docker/volumes/volnginx1/_data #查看对应的挂载目录,发现有数据
docker exec -it myvolnginx1 bash # 运行宿主机
cd /usr/share/nginx/html/ # 然后对文件修改,会发现使用宿主机查看文件也会被修改
docker run -d --name myvolnginx2 -v volnginx2:/usr/share/nginx/html/:ro nginx:1.24.0 # 带有:ro
# 然后进入容器中删除对应目录,会发现不允许。不过可以在宿主机上可以修改
--mount 指定参数并创建管理卷
示例:
shell
docker run -d --name mynginx3 --mount 'src=nginxvol3,dst=/usr/share/nginx/html' + 镜像
参数:
shell
type 表示bind volume tmpfs
src 命名卷,不带有表示匿名卷
dst 表示管理卷
卷的生命周期
如果我们只是删除容器,不会删除卷,此时在宿主机查看对应路径,发现还有对应内容,但是如果我们使用docker volume rm删除卷,就看不到对应目录的内容了。
卷的共享
我们可以-v来把多个容器绑定到同一个卷。实现多个容器共享卷的效果
绑定卷 bind
使用docker bind绑定卷,如果容器卷对应目录在绑定前有东西,但是宿主机对应目录绑定时没有东西,那么容器卷就要先清空了
--mount
-
--mount的src表示宿主机目录
-
如果宿主机对应目录不存在,不可以创建绑定卷
-
如果宿主机对应目录没有文件,容器对应目录也要清空
示例:
shell
docker run -d --name mynginx7 --mount 'type=bind,src=/data/maxhou/testmountbind,dst=/usr/share/nginx/html' + 镜像
-v
-
-v 只有一个参数和volume不一样,第一个参数多了一个宿主机目录的参数
-
如果宿主机对应目录不存在,会自动在宿主机创建对应目录
-
如果宿主机对应目录没有文件,容器对应目录也要清空
示例:
shell
docker run -d --name mynginx6 -v /data/maxhou/testbind:/usr/share/nginx/html/ + 镜像
共享和管理卷相同
临时卷 tmpfs (只能linux使用)
- 如果我们刚好绑定了容器内部已经存在文件的目录,那么目录里面的内容会被清理掉
- 容器可以正常访问对应目录,对于容器来说,和文件没有区别,但是本质上存储的数据都在内存上。如果我们重启容器,就会发现对应目录空了。
示例:
shell
docker run -d --name mynginx10 -tmpfs /test1 + 镜像 # 这个/test1表示容器内的数据
--mount 指明多参数
示例:
shell
docker run -d --name mynginx11 --mount type=tmpfs,dst=/test2 + 镜像
案例:
shell
docker run -d --name mynginx18 -p 8091:80 --mount type=tmpfs,dst=/usr/share/nginx/html,tmpfs-size=1m
docker exec -it mynginx18 bash
cd /usr/share/nginx/ # 发现目录是空的,这是因为被覆盖了
# 如果我们向对应目录放内容,如果发现文件大小大于规定的大小,会提示空间不足
# 如果我们想在宿主机查找对应文件:/data/var/lib/docker/... 我们可以使用find查找创建的文件
# 如果容器消失,在宿主机就看不到对应文件了
实战案例
MYSQL灾难恢复
创建绑定卷:
shell
docker run --name mysql2 -v /data/maxhou/mysql2test:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123 -d mysql:5.7 # 在docker官方搜索mysql镜像,然后找到对应版本修改密码和宿主机路径即可
# 然后创建一个database table
删除容器:
shell
docker rm -f mysql2
启动新的容器绑定宿主机目录:
shell
docker run --name mysql2new -v /data/maxhou/mysql2test:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123 -d mysql:5.7
docker exec -it mysql2new bash
# 然后根据密码进入mysql,查询database table
# 发现仍然存在数据
结论:可以使用绑定卷来防止容器删除导致数据丢失,实现持久化
不同卷的应用场景
volume:不需要规划具体目录场景
bind:控制谁来使用哪个目录
tmpfs:用于敏感文件,容器关闭后文件就消失了
存储卷在实际研发带来的问题
-
存储卷是有状态应用。如果我们希望不同主机共享存储卷信息,需要搭建NFS或者其他共享存储工具,实现共享存储。docker不能自己完成这样的功能。
-
启动参数未知,每次容器启动都需要很多参数------为此需要容器编排工具,比如k8s
-
复杂场景仍然需要运维,mysql扩容缩容、为什么挂掉,mysql的规划需要运维规划。没有工具解决