[Docker#9] 存储卷 | Volume、Bind、Tmpfs | -v/mount | MySQL 灾难恢复 | 问题

ops/2024/11/18 2:25:21/

目录

1. 什么是存储卷?

2. 生活案例

3. 为什么需要存储卷?

4. 存储卷分类

一. 管理卷 Volume

创建卷

通过 -v 或 --mount 指定

1. -v 语法

命令格式

参数说明

2. --mount 语法

命令格式

参数说明

验证

二. 绑定卷 (Bind Mount)

1. 绑定卷概述

2. 创建绑定卷

2.1 使用 -v 参数创建绑定卷

2.2 使用 --mount 参数创建绑定卷

3. 操作案例

使用 -v 创建绑定卷

4. 绑定卷共享

三. 临时卷 (tmpfs)

1. 临时卷概述

2. 创建临时卷

方式一:使用 --tmpfs 参数创建

方式二:使用 --mount 参数创建

3. 操作案例

使用 --tmpfs 创建临时卷

四. 运用

MySQL 灾难恢复

实战目的

实战步骤

五. 常见问题

Volume、Bind、Tmpfs 的使用时机

问题

1. 跨主机使用

2. 启动参数未知

3. 复杂场景仍需运维


1. 什么是存储卷?
  • 存储卷是指将宿主机上的某个目录与容器内的某个目录建立绑定关系
  • 这意味着当容器在这个目录下写入数据时,实际上是直接写入宿主机上的对应目录。
  • 存储卷的本质是一个文件或目录,它允许数据绕过容器的联合文件系统,直接存在于宿主机上,从而实现宿主机与容器之间的数据共享。
  • 容器和宿主机的数据读写 是同步的。

2. 生活案例

存储卷就像租用了一个地下室,你可以通过这把“钥匙”(即映射关系)来使用房子外的空间。即使房子(容器)被毁,地下室(存储卷)中的数据仍然安全无损。

3. 为什么需要存储卷?
  • 数据丢失问题:对于需要持久化的数据,容器销毁后其读写层的数据也会丢失。存储卷确保了即使容器被删除,数据也能被保存。
  • 性能问题:UnionFS 对于频繁的读写操作效率较低,而存储卷可以提供更好的I/O性能。
  • 宿主机与容器互访不便:通过存储卷,可以轻松地在宿主机与容器之间共享文件,无需使用 docker cp 命令。
  • 容器间共享不便:存储卷也方便了不同容器间的文件共享。
4. 存储卷分类

Docker提供了三种主要的存储卷类型:

  • volume:由Docker管理,默认映射到 /var/lib/docker/volumes/ 下,适合临时存储。
  • bind mount:映射到宿主机的指定路径,适用于需要精确控制宿主机目录的情况。
  • tmpfs mount:映射到宿主机的内存中,适合需要高速度临时存储的场景.

对于 mount 的理解:

可以类比为将磁盘挂载到操作系统上,操作系统会提供一个访问接口。同样,Docker 的 mount 也是将一个资源(如存储卷)挂载到容器中,并提供一个访问路径。

一. 管理卷 Volume

创建卷

命令操作

  • docker volume create [OPTIONS] [VOLUME]:创建存储卷。
  • docker volume inspect [OPTIONS] VOLUME [VOLUME...]:查看卷的详细信息。
  • docker volume ls [OPTIONS]:列出所有卷。
  • docker volume rm [OPTIONS] VOLUME [VOLUME...]:删除卷。
  • docker volume prune [OPTIONS]:清理所有未使用的卷。

实操:

通过 -v--mount 指定

1. -v 语法
命令格式
docker run -v name:directory[:option]
参数说明
  • name:绑定的现有卷的名称,可以省略,此时会创建一个新的匿名卷。
  • directory:数据卷在容器内部的路径。
  • option:可以指定 ro 表示只读,此时只有宿主机可以修改数据卷,容器只读。

操作:

注意

  • 即使删除容器,存储卷内的内容依然存在。
  • 如果指定存储卷名时,存储卷不存在,Docker 会自动创建一个新的命名卷。新创建的:

2. --mount 语法
命令格式
docker run --mount key=value [key=value ...]
参数说明
  • type:存储卷类型,指定 volume 表示数据卷。
  • src:对于命名卷,表示卷名;对于匿名卷,此字段省略。
  • dst:文件在容器的挂载路径。
  • ro:只读方式挂载。

使用 --mount 创建命名卷

假设我们要创建一个命名卷 test_vm_3 并挂载到 Nginx 容器/usr/share/nginx/html 目录下,且设置为只读。

示例

docker run -d --name nginx-read-only --mount type=volume,src=test_vm_3,dst=/usr/share/nginx/html,ro nginx
验证
  1. 进入容器内部:
docker exec -it nginx-read-only /bin/bash
  1. 尝试修改 /usr/share/nginx/html 目录下的文件,会提示 Read-only file system,表示该目录是只读的。

对于管理卷 volume 默认路径的查看

总结:

  • -v 语法:简单直观,适用于快速创建和挂载数据卷。
  • --mount 语法:更加灵活,支持更多选项,适用于复杂场景。
  • 数据卷:无论是命名卷还是匿名卷,都可以实现宿主机与容器之间的数据共享
  • 数据卷在容器删除后依然保留。

二. 绑定卷 (Bind Mount)

1. 绑定卷概述
  • 绑定卷(Bind Mount)是将宿主机上的某个目录直接挂载到容器内的某个目录。
  • 这种方式允许容器和宿主机之间共享文件和目录,且数据直接存储在宿主机的文件系统中。

2. 创建绑定卷

2.1 使用 -v 参数创建绑定卷
  • 功能:完成卷映射。

语法

docker run -v host-dir:container-dir[:options] ...

参数

  • host-dir:宿主机目录,不同于管理卷。
  • container-dir:卷映射到容器的目录。
  • options:选项,如 ro 表示只读。

样例

docker run -d \-it \--name devtest \-v "$(pwd)"/target:/app \nginx:latest
2.2 使用 --mount 参数创建绑定卷
  • 功能:完成目录映射。
  • 语法
docker run --mount 'type=bind,source=host-dir,target=container-dir,readonly'

关键参数

  • type:类型,表示 bind
  • sourcesrc:宿主机目录,不同于管理卷。
  • destinationdsttarget:文件或目录挂载在容器中的路径。
  • roreadonly:只读方式挂载。

样例

docker run -d \-it \--name devtest \--mount type=bind,source="$(pwd)"/target,target=/app \nginx:latest

对比观察:

3. 操作案例

使用 -v 创建绑定卷
  1. 创建容器
docker run -d -p 8080:80 --name bind2 -v /data/myworkdir/fs/webapp2:/usr/share/nginx/html nginx:1.22.1

注意:如果 webapp2 目录不存在,启动不会报错,这是 -v--mount 方式的区别。

  1. 查看挂载信息
docker inspect bind2

输出示例:

  1. 进入容器终端,查看挂载点目录
docker exec -it bind2 ls /usr/share/nginx/html

宿主机上查看:

ll /data/myworkdir/fs/webapp2

容器中的 /usr/share/nginx/html 目录原本存在的文件消失了,这是因为 bind mount 模式会覆盖容器内的原有内容,而 volume 模式则不会。这是两者最大的不同点。

  1. 在宿主机上添加 index.html
echo "Hello bit bind2 mount" > /data/myworkdir/fs/webapp2/index.html

查看:

  1. 通过浏览器访问,可以看到容器已经读取到宿主机的共享内容。
  2. 删除容器,查看宿主机上的文件
docker stop bind2
docker rm bind2
ll /data/myworkdir/fs/webapp2

宿主机上的文件依然存在,说明容器删除并不影响 bind 映射。

4. 绑定卷共享

  1. 启动两个绑定卷,都绑定到宿主机的同一个目录
docker run -d -p 8770:80 --name bind3 -v /data/myworkdir/fs/webapp1:/usr/share/nginx/html nginx:1.22.1
docker run -d -p 7705:80 --name bind4 -v /data/myworkdir/fs/webapp1:/usr/share/nginx/html nginx:1.22.1
  1. 访问两个页面,可以看到相应内容一样:
curl 127.0.0.1:8770
curl 127.0.0.1:7705

查看

  1. 修改 index.html
echo "bind mount after edit" > /data/myworkdir/fs/webapp1/index.html
  1. 再次访问两个页面,可以看到我们实现了容器间的数据共享:
curl 127.0.0.1:8770
curl 127.0.0.1:7705

  1. 清理空间
docker stop bind3
docker rm bind3
docker stop bind4
docker rm bind4

三. 临时卷 (tmpfs)

1. 临时卷概述

临时卷(tmpfs)的数据存储在内存中,不在容器和宿主机的文件系统中。因此,tmpfs 具有以下特点:

  • 数据仅存在于内存中,容器停止后数据会丢失。
  • 不能在容器之间共享 tmpfs 挂载。
  • 仅在 Linux 上运行 Docker 时可用。
2. 创建临时卷
方式一:使用 --tmpfs 参数创建
  • 功能:完成临时卷映射。
  • 语法
--tmpfs /app
  • 样例
docker run -d \-it \--name tmptest \--tmpfs /app \nginx:1.22.1
方式二:使用 --mount 参数创建
  • 功能:完成目录映射。
  • 语法
--mount 'type=tmpfs,destination=/app,tmpfs-size=1m,tmpfs-mode=0770'
  • 关键参数
    • type:类型,表示 tmpfs
    • destinationdsttarget:挂载在容器中的路径。
    • tmpfs-size:tmpfs 挂载的大小(以字节为单位)。默认无限制。
    • tmpfs-mode:tmpfs 的八进制文件模式。例如,700 或 0770。默认为 1777 或全局可写。
  • 样例
docker run -d \-it \--name tmptest \--mount type=tmpfs,destination=/app \nginx:latest

3. 操作案例

使用 --tmpfs 创建临时卷

  1. 创建临时卷并启动容器
docker container run --name tmpfs1 -d -p 80:80 --tmpfs /usr/share/nginx/html nginx:1.22.1

进入容器查看挂载点目录

docker exec -it tmpfs1 bash
cd /usr/share/nginx/html/
ls -l

发现容器中的 /usr/share/nginx/html 目录原本存在的文件被覆盖了。

添加一个首页

echo "Hello bit from tmpfs" > index.html
cat index.html

浏览器查看
访问 http://localhost,可以看到页面显示 "Hello bit from tmpfs"。

说明:

  • 重启容器后可以发现, tmpfs 的内容完全消失了,说明内容是存在内存中的
  • tmpfs 的内容不是存储在容器的可写层中。

总结

  • 临时卷(tmpfs)是一种将数据存储在内存中的方式,适用于需要临时存储数据的场景。
  • tmpfs 的数据在容器停止后会丢失,且不能在容器之间共享。
  • 通过 --tmpfs--mount 参数可以创建 tmpfs 挂载,但需要注意 tmpfs 的大小限制和内存占用。

四. 运用

MySQL 灾难恢复

实战目的

掌握挂载卷的使用,将 MySQL 的业务数据存储到外部,以便在容器故障或服务器重启后能够快速恢复数据。

实战步骤

准备镜像

docker pull mysql:5.7

创建容器

docker container run --name mysql-demo -e MYSQL_ROOT_PASSWORD=bite -itd -v /data/myworkdir/mysql-data:/var/lib/mysql mysql:5.7
  • -e MYSQL_ROOT_PASSWORD=bite:设置 MySQL 的 root 密码。
  • -v /data/myworkdir/mysql-data:/var/lib/mysql:将宿主机的 /data/myworkdir/mysql-data 目录挂载到容器/var/lib/mysql 目录。

查看容器挂载信息

docker container inspect mysql-demo | grep "Mounts" -A 10

输出示例:

连接 MySQL 并创建数据库和表

docker container exec -it mysql-demo /bin/bash
bash-4.2# mysql -u root -p

在 MySQL 中执行以下命令:

在宿主机中查看 volume

ll /data/myworkdir/mysql-data/

输出示例:

进入 user 目录查看:

cd /data/myworkdir/mysql-data/user
ll

输出示例:

模拟灾难情况

docker stop mysql-demo
docker rm mysql-demo
  • 假设服务器突然断电,重启后 MySQL 无法启动。
  • 为了节省磁盘空间,删除了所有停止的容器

恢复数据

docker container run --name mysql-demo-new -e MYSQL_ROOT_PASSWORD=bite -itd -v /data/myworkdir/mysql-data:/var/lib/mysql mysql:5.7
  • 重新启动容器,确保目录映射一致。

验证数据恢复

docker exec -it mysql-demo-new bash
mysql -u root -p
Enter password: bite

在 MySQL 中执行以下命令:

  • 进入容器并连接 MySQL,发现数据还在~

释放空间

docker stop mysql-demo-new
docker rm mysql-demo-new

五. 常见问题

Volume、Bind、Tmpfs 的使用时机

Volume:

  • 适用场景:当不需要规划具体目录时使用,如日志文件、数据库数据等。
  • 特点:是 Docker 宿主机文件系统的一部分

Bind:

  • 适用场景:当目录需要提前规划时使用,例如 MySQL 数据目录需要较大空间。
  • mysql 的目录需要个空间大的,其他服务有不占用的时候,用 volume 就不太合 适了
  • 特点:依赖于主机的目录结构和操作系统。

Tmpfs:

  • 适用场景:用于存储敏感文件,文件不希望存储在宿主机的可写层或容器内。

问题

1. 跨主机使用
  • 问题: Docker 存储卷默认使用宿主机的本地文件系统,不支持跨主机调度。
  • 解决方案: 可以通过搭建共享存储(如 NFS)来实现跨主机存储,但依赖运维人员能力。
  • 趋势: 应用存储和数据分离,分布式存储方案(如 S3、NFS)逐渐流行。
2. 启动参数未知
  • 问题: 容器启动参数较多,容易忘记。
  • 解决方案: 使用容器编排工具记录启动参数,通过文件读取启动配置。
  • 工具: Kubernetes(k8s)或云厂商的企业版编排软件。
3. 复杂场景仍需运维
  • 问题: 对于有状态且需要持久化的集群化组件(如 MySQL 主从),部署和维护需要丰富的运维经验和知识。
  • 挑战: 需要了解集群规模、节点数量、数据分布等,以便于故障修复和扩展。
  • 现状: 复杂场景仍依赖人力,难以完全自动化。

http://www.ppmy.cn/ops/134602.html

相关文章

SpringBoot有几种获取Request对象的方法

HttpServletRequest 简称 Request,它是一个 Servlet API 提供的对象,用于获取客户端发起的 HTTP 请求信息。例如:获取请求参数、获取请求头、获取 Session 会话信息、获取请求的 IP 地址等信息。 那么问题来了,在 Spring Boot 中…

【网络安全面经】技术性问题

1.SQL注入原理 主要基于Web应用程序对用户输入数据的合法性缺乏严格的判断或过滤 2.windows上提权的方式和linux提权方式 windows:本地溢出漏洞提权,AT(计划任务提权),SC(创建服务提权),PS(微软官方工具pstool),数据…

集群聊天服务器(2)Json介绍

目录 Json序列化Json反序列化 大家之间交流用json,想要发送数据,就把数据序列化成json,想要接收数据,就反序列化成自己程序的语言。 Json序列化 可以直接赋值一个容器对象 js[‘xx’]vec; #include "json.hpp" using jsonnlohman…

蓝桥杯每日真题 - 第15天

题目:(钟表) 题目描述(13届 C&C B组B题) 解题思路: 理解钟表指针的运动: 秒针每分钟转一圈,即每秒转6度。 分针每小时转一圈,即每分钟转6度。 时针每12小时转一圈…

python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具

python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具 文章目录 python实战案例----使用 PyQt5 构建简单的 HTTP 接口测试工具项目背景技术栈用户界面核心功能实现结果展示完整代码总结 在现代软件开发中,测试接口的有效性与响应情况变得尤为重要。本文将指导…

Android LiveData 处理数据倒灌的几种措施

LiveData MutableLiveDataSingleLiveEventUnFlowLiveDataUnPeekLiveData扩展1. 为什么Fragment中要使用viewLifecycleOwner代替this2. 如果使用了Fragment的this,有可能产生的问题 参考地址 MutableLiveData 粘性特性 定义 MutableLiveData的粘性特性是指当一个观察…

嵌入式硬件杂谈(二)-芯片输入接入0.1uf电容的本质(退耦电容)

引言:对于嵌入式硬件这个庞大的知识体系而言,太多离散的知识点很容易疏漏,因此对于这些容易忘记甚至不明白的知识点做成一个梳理,供大家参考以及学习,本文主要针对芯片输入接入0.1uf电容的本质的知识点的进行学习。 目…

信捷PLC转以太网连接电脑方法

信捷XC/XD/XL等系列PLC如何上下载程序?可以选择用捷米特JM-ETH-XJ模块轻松搞定,并不需要编程,即插即用,具体看见以下介绍: 产品介绍 捷米特JM-ETH-XJ是专门为信捷PLC转以太网通讯面设计,可实现工厂设备信息化需求,对…