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

embedded/2024/11/19 13:51:47/

目录

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/embedded/138778.html

相关文章

《Beginning C++20 From Novice to Professional》第十三章 Operator Overloading

操作符重载主要是让自定义类型有和内置类型类似的自然的操作,比如字符串的连接、矩阵的运算等等用操作符比使用成员函数(虽然也是成员函数)要直观一些 本章我们可以学到: Implementing Operators for a Class 上一章我们实现的Truckload类有一个寻找最大体积的函数,其中…

Mybatis框架之单例模式 (Singleton Pattern)

MyBatis 框架中也使用到了单例模式 (Singleton Pattern),主要体现在 SqlSessionFactory 的创建和管理上。通过单例模式,MyBatis 可以确保整个应用程序中只创建一个 SqlSessionFactory 实例,从而有效地管理数据库连接资源并提高性能。下面将详…

wsl配置ubuntu22.04,并配置docker

wsl配置ubuntu22.04,并配置docker 文章目录 wsl配置ubuntu22.04,并配置docker一、在Windows上安装Linux子系统前提条件安装步骤 二、wsl安装系统到其他盘①查看wsl运行状态,将其保持在关闭状态②导出当前Linux的镜像③注销之前的系统并检查④…

系统思考—跳出症状看全局

在和企业创办人交流中,经常听到这样的疑问:“为什么我们试了这么多办法,问题却还是没有解决?”其实很多时候,根本原因并不在于对策不到位,而是连问题的本质都没找对。 曾经和一家企业合作,为了解…

大数据-225 离线数仓 - 目前需求分析 指标口径 日志数据采集 taildir source HDFS Sink Agent Flume 优化配置

点一下关注吧!!!非常感谢!!持续更新!!! 目前已经更新到了: Hadoop(已更完)HDFS(已更完)MapReduce(已更完&am…

栈Stack和队列Queue

目录 一、栈 (1)用数组实现 (2)用单链表实现 (3)用标注尾结点的单链表实现 (4)用双向链表实现 2、栈的实际应用 (1)改变元素的序列 (2&am…

学习日记_20241110_聚类方法(K-Means)

前言 提醒: 文章内容为方便作者自己后日复习与查阅而进行的书写与发布,其中引用内容都会使用链接表明出处(如有侵权问题,请及时联系)。 其中内容多为一次书写,缺少检查与订正,如有问题或其他拓展…

R语言/Rstudio 报错

记录R语言和Rstudio的报错: 1. Error 28 (inotify_add_watch: No watches available) File monitoring failed for project at "~xxx" Error 28 (inotify_add_watch: No watches available) Features disabled: R source file indexing, Diagnostics不少…