Docker Volume(存储卷)使用指南
什么是存储卷?
在 Docker 中,存储卷(Volume)是容器持久化数据的核心机制。简单来说,存储卷就是将宿主机文件系统中的某个目录与容器文件系统中的某个目录建立绑定关系。这样一来,当容器内部程序在该目录下写入数据时,数据会直接写入宿主机的绑定目录。
在宿主机上,这个与容器绑定的目录就被称为存储卷。卷的本质就是宿主机上的一个文件或目录,它绕过了默认的联合文件系统(Union File System),能够直接存在于宿主机上。这样做的好处是数据不会随着容器的删除而丢失,同时还能实现宿主机与容器之间的数据共享。
举个例子:
如果将宿主机的 /data/web 目录与容器内部的 /container/data/web 目录绑定,那么当容器内的进程往 /container/data/web 中写入数据时,实际上数据是写在宿主机的 /data/web 目录里。反之亦然——宿主机中对 /data/web 的操作,也会同步到容器内部目录。这使得容器和宿主机之间的数据读写保持一致,实现了跨环境的数据共享。
我们可以把存储卷类比为“房子外的地下室”。容器就像是房子,卷就是地下室。当我们把卷绑定到容器里,就好比我们拥有了地下室的钥匙,可以把房子以外的空间也利用起来。
假设有一天龙卷风来了,房子被摧毁了,但地下室依然完好无损。这就好比容器被删除了,但存储卷中的数据依然存在,不会受到影响。等新房子(新的容器)建好以后,依然可以用同一把钥匙进入地下室继续使用原来的数据。
此外,地下室(存储卷)还可以被多个房子(容器)共享使用。这样,不同的房子可以通过地下室来交换物品,实现数据的共享和协作。
为什么需要存储卷?
容器天生适合运行无状态应用,但在实际生产中,很多业务都需要持久化数据。如果仅依赖容器自身的文件系统,就会遇到很多问题。存储卷的出现,正是为了解决这些痛点。
1. 数据丢失问题
容器从业务角度可以分为两类:
- 无状态容器:数据无需持久化,例如 Nginx、前端应用等。
- 有状态容器:数据需要持久化,例如 MySQL、Kafka、Redis 等。
容器文件系统的本质,是在镜像层之上临时创建一个读写层。运行中容器对文件的所有修改,都发生在这个读写层。但当容器被删除时,读写层也会随之消失,导致数据无法保留。
虽然容器的设计初衷是尽量保持无状态,方便快速部署和迁移,但实际业务离不开持久化需求。因此,Docker 引入了卷(Volume)的概念,专门用于解决数据持久化的问题。
2. 性能问题
容器默认的联合文件系统(UnionFS)在处理文件修改和删除操作时性能较低。如果是对 I/O 性能要求较高的应用(如 Redis 持久化、数据库写入操作),UnionFS 的效率会成为瓶颈。而卷直接绕过 UnionFS,与宿主机文件系统交互,极大提升了读写性能。
3. 宿主机与容器之间的数据交互不便
如果没有卷,宿主机和容器之间的数据传输需要通过 docker cp 等命令完成。这种方式繁琐、效率低,也不利于应用自动化管理。而通过卷,宿主机和容器可以直接共享同一份数据,交互更加自然。
4. 多容器之间的数据共享困难
在复杂业务场景下,往往有多个容器需要访问同一份数据。例如,一个应用容器需要与一个日志采集容器共享日志文件。如果不借助卷,容器之间共享数据会变得非常困难。而卷可以轻松解决这个问题,让多个容器挂载同一个目录,从而实现高效的数据共享。
存储卷的分类
在 Docker 中,存储卷是实现数据持久化与共享的关键机制。目前,Docker 提供了三种主要的方式将宿主机的数据挂载到容器中:
1. Volume(卷)
特点:由 Docker 引擎统一管理,默认存放在宿主机的
/var/lib/docker/volumes目录下。使用方式:用户只需在容器中指定挂载点,至于宿主机上的实际目录位置,由 Docker 自动创建或使用已有目录完成绑定。
优点:
- 简化了用户操作,不需要手动管理宿主机目录。
- 与宿主机文件系统的耦合度低,容器迁移更方便。
- 可以配合 Volume Driver(如 NFS、云存储插件)扩展功能。
缺点:用户无法直接指定宿主机目录位置,可见性和可控性相对较低。
适用场景:适合大多数需要持久化数据的容器,尤其在生产环境下使用最为普遍。
2. Bind Mount(绑定挂载)
特点:将宿主机上的指定目录或文件与容器内目录直接绑定。
使用方式:需要在宿主机和容器中同时指定路径,建立明确的映射关系。
优点:
- 灵活性强,用户可以精确控制宿主机与容器共享的目录。
- 容器可以直接访问宿主机上的已有文件和目录。
缺点:
- 与宿主机文件系统耦合度高,不利于容器在不同环境间迁移。
- 如果宿主机路径错误,可能导致容器挂载失败或不可用。
适用场景:常用于开发调试阶段,例如代码热更新、日志调试等场景,或者需要指定目录来存储数据的场景,如
MySQL等需要独立的大块空间。
3. tmpfs Mount(内存挂载)
特点:将数据直接挂载到宿主机的内存中,而不是持久化到磁盘。
使用方式:通过
--mount type=tmpfs指定挂载点,数据只存在于内存里。优点:
- 读写速度快,性能极高。
- 数据不会落盘,安全性更高(适合存放敏感数据)。
缺点:
- 容器停止后数据即会丢失,无法持久化。
适用场景:适合需要高性能临时存储的场景,例如存放缓存文件、临时会话数据等。

下面是对三种存储方式的一个表格直观对比:
| 特性 | Volume(卷) | Bind Mount(绑定挂载) | tmpfs Mount(内存挂载) |
|---|---|---|---|
| 管理方式 | 由 Docker 引擎统一管理,默认存放在 /var/lib/docker/volumes |
用户手动指定宿主机目录或文件 | 数据存放在宿主机内存中 |
| 宿主机耦合度 | 低,目录位置由 Docker 管理,迁移方便 | 高,依赖宿主机具体路径 | 无(只依赖宿主机内存) |
| 是否持久化 | ✅ 是,容器删除后数据仍在 | ✅ 是,容器删除后数据仍在 | ❌ 否,容器停止后数据丢失 |
| 性能 | 中等(绕过 UnionFS,性能较好) | 中等(直接访问宿主机目录) | 高(纯内存读写,最快) |
| 优点 | 简单、解耦、适合生产环境,可支持 Volume Driver | 灵活,可直接使用宿主机已有目录或文件 | 高速读写,数据不落盘,安全性好 |
| 缺点 | 无法自定义宿主机目录,透明度较低 | 与宿主机耦合度高,迁移不便,易出错 | 数据不可持久化,容量受内存限制 |
| 适用场景 | 数据库、持久化业务(MySQL、Kafka 等) | 开发调试、代码热更新、日志共享、指定目录 | 缓存、会话、临时文件、高性能应用 |
创建和管理存储卷
Docker 提供了一套命令来专门管理卷(Volume)。这些命令可以帮助我们创建、查看、删除以及清理卷。下面我们详细看一下。
方式一:通过 Volume 命令操作
1. 创建卷:docker volume create
docker volume create my_volume
功能:创建一个新的存储卷。
关键参数:
-d, --driver:指定存储驱动,默认是local。--label:为卷添加元数据标签,方便管理。
示例:
# 创建一个默认卷
docker volume create my_volume
# 创建一个带标签的卷
docker volume create --label project=blog_data blog_volume
创建完成后,可以在宿主机 /var/lib/docker/volumes/ 目录下找到对应的卷。
2. 查看卷信息:docker volume inspect
docker volume inspect my_volume
功能:查看卷的详细信息,例如挂载点、驱动、标签等。
关键参数:
-f:指定输出格式,例如json。
示例:
# 查看卷的详细信息
docker volume inspect my_volume
# 只输出卷的挂载路径
docker volume inspect -f '{{ .Mountpoint }}' my_volume
输出结果通常会包含卷的具体路径(Mountpoint),我们可以确认卷和宿主机之间的真实绑定位置。
3. 列出卷:docker volume ls
docker volume ls
功能:显示当前所有的卷。
关键参数:
--format:指定输出格式,例如json、table。--filter, -f:按条件过滤卷,例如驱动类型或标签。-q:仅显示卷的名称(安静模式)。
示例:
# 列出所有卷
docker volume ls
# 只显示卷的名称
docker volume ls -q
# 过滤出使用 local 驱动的卷
docker volume ls -f driver=local
4. 删除卷:docker volume rm
docker volume rm my_volume
功能:删除指定卷(前提是该卷没有被任何容器使用)。
关键参数:
-f, --force:强制删除正在使用的卷。
示例:
# 删除一个卷
docker volume rm my_volume
# 强制删除卷
docker volume rm -f blog_volume
⚠️ 注意:如果卷被容器使用,直接删除会失败。除非使用 -f 强制删除,但这可能导致容器数据丢失。
5. 清理未使用的卷:docker volume prune
docker volume prune
功能:清理掉所有未被容器使用的卷。
关键参数:
--filter:按条件过滤要删除的卷。-f, --force:跳过确认提示,直接删除。
示例:
# 删除所有未使用的卷(执行前会有确认提示)
docker volume prune
# 强制删除所有未使用的卷
docker volume prune -f
# 删除创建时间早于 24 小时的卷
docker volume prune --filter "until=24h"
这个命令在日常开发中非常有用,尤其是反复测试创建容器后会产生很多孤立卷,通过 prune 可以一键清理,避免宿主机磁盘空间被占满。
小结
通过这些命令,我们可以完成存储卷的生命周期管理:
create→ 创建卷inspect→ 查看卷信息ls→ 列出所有卷rm→ 删除指定卷prune→ 清理未使用卷
📌 建议在开发调试时,定期使用 docker volume ls 和 docker volume prune,保持宿主机的磁盘空间整洁。
方式二:在运行容器时挂载卷
除了通过 docker volume create 命令手动创建卷外,我们还可以在运行容器时直接指定挂载,这样会自动创建并绑定卷。Docker 提供了两种常见方式:-v 和 --mount。
1. 使用 -v 参数
-v 是 Docker 早期提供的挂载方式,语法相对简洁。
语法:
docker run -v [卷名或宿主机路径]:[容器内路径][:选项] ...
参数说明:
- 第一个参数:卷名称(如
myvol)或宿主机目录(如/data/logs)。 - 第二个参数:容器内挂载目录。
- 第三个参数(可选):挂载选项,例如
ro表示只读。
- 第一个参数:卷名称(如
示例 1:挂载命名卷
docker run -d \
--name devtest \
-v myvol2:/app \
nginx:latest
这条命令会自动创建一个名为 myvol2 的卷,并挂载到容器的 /app 目录。
通过 docker inspect devtest 可以看到挂载详情:
"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
示例 2:挂载宿主机目录
docker run -d \
--name devtest2 \
-v /home/user/logs:/var/log/nginx \
nginx:latest
这里将宿主机的 /home/user/logs 目录映射到容器的 /var/log/nginx,日志会直接写入宿主机目录。
示例 3:只读挂载
docker run -d \
--name devtest3 \
-v myvol3:/data:ro \
nginx:latest
这里的卷挂载到容器内 /data,但容器只能读取,无法写入。
2. 使用 --mount 参数
--mount 是 Docker 较新的推荐方式,语法比 -v 更加明确和可读。
语法:
--mount type=<类型>,source=<卷名或宿主机路径>,target=<容器内路径>[,选项]
关键参数:
type:挂载类型(volume、bind或tmpfs)。source/src:卷名或宿主机目录。destination/dst/target:容器内的挂载路径。readonly/ro:只读挂载。
示例 1:挂载命名卷
docker run -d \
--name devtest \
--mount type=volume,source=myvol2,target=/app \
nginx:latest
输出 docker inspect devtest 的结果与 -v 类似:
"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
示例 2:挂载宿主机目录(bind mount)
docker run -d \
--name devtest2 \
--mount type=bind,source=/home/user/logs,target=/var/log/nginx \
nginx:latest
这和 -v /home/user/logs:/var/log/nginx 等价,但语法更清晰。
示例 3:只读挂载
docker run -d \
--name devtest3 \
--mount type=volume,source=myvol3,target=/data,readonly \
nginx:latest
容器内 /data 目录为只读。
3. -v 与 --mount 的区别
| 对比项 | -v 参数 |
--mount 参数 |
|---|---|---|
| 语法 | 简洁,但容易出错(顺序重要) | 结构化,语义更清晰 |
| 功能覆盖 | 支持 volume 和 bind |
支持 volume、bind、tmpfs |
| 可读性 | 相对较差 | 更好,推荐生产环境使用 |
| 常见用途 | 开发测试、快速挂载 | 生产环境,复杂挂载场景 |
📌 建议:
- 在 开发阶段 可以图方便用
-v。 - 在 生产环境 建议统一使用
--mount,避免出错,也方便团队成员理解配置。
方式三:Dockerfile 匿名卷
通过 Dockerfile 的 VOLUME 可以创建 docker 管理卷,我将在后面的 Dockerfile 章节中详细介绍
三种存储卷操作实例
Docker 命令创建管理卷
1. 创建存储卷
docker volume create test_volume
输出结果:
test_volume
2. 使用卷运行容器
将刚才创建的卷挂载到 Nginx 容器中:
docker container run --name nginx1 -d -p 5566:80 \
-v test_volume:/usr/share/nginx/html \
nginx:1.22.1
同样,我们也可以运行另一个容器,挂载到同一个卷:
docker container run --name nginx2 -d -p 5577:80 \
-v test_volume:/usr/share/nginx/html \
nginx:1.22.1
这样两个容器共享同一个卷,数据会同步。
3. 查看存储卷列表
docker volume ls
输出结果:
DRIVER VOLUME NAME
local test_volume
4. 查看卷的详细信息
docker volume inspect test_volume
输出结果(部分):
[
{
"CreatedAt": "2025-09-02T12:23:12+08:00",
"Driver": "local",
"Mountpoint": "/data/var/lib/docker/volumes/test_volume/_data",
"Name": "test_volume",
"Options": null,
"Scope": "local"
}
]
可以看到 Mountpoint 对应宿主机上的真实目录。
5. 查看宿主机目录
进入卷对应的目录,可以看到 Nginx 默认的网页文件:
cd /data/var/lib/docker/volumes/test_volume/_data
ls -l
输出结果:
total 16
drwxr-xr-x 2 root root 4096 Mar 16 12:32 ./
drwx-----x 3 root root 4096 Mar 16 12:16 ../
-rw-r--r-- 1 root root 497 Oct 19 16:02 50x.html
-rw-r--r-- 1 root root 615 Oct 19 16:02 index.html
6. 查看容器挂载信息
docker inspect nginx1
输出结果(部分):
"Mounts": [
{
"Type": "volume",
"Name": "test_volume",
"Source": "/data/var/lib/docker/volumes/test_volume/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
]
说明 test_volume 已经挂载到容器的 /usr/share/nginx/html 目录中。
7. 修改宿主机文件并同步到容器
修改宿主机上的 index.html:
cd /data/var/lib/docker/volumes/test_volume/_data
echo "Hello Volume" > index.html
然后通过浏览器访问 http://宿主机IP:5566,即可看到更新后的内容,证明宿主机和容器数据同步:

8. 停止并删除容器
docker stop nginx1
docker rm nginx1
卷不会随着容器的删除而消失,数据依然存在。
通过以上实验可以得出:
- 宿主机和容器之间数据是实时同步的。
- 容器删除后,卷仍然保留,数据不会丢失。
Docker -v 创建管理卷
下面演示如何使用 -v 参数创建和挂载存储卷,并验证 只读模式 (ro) 的效果。
1. 使用 -v 创建卷并启动容器
通过 -v 指定一个新卷 test_volume2,挂载到 Nginx 容器的 /usr/share/nginx/html 目录,并设置为只读模式:
docker container run --name nginx2 -d -p 5566:80 \
-v test_volume2:/usr/share/nginx/html:ro \
nginx:1.22.1
2. 查看卷信息
使用 docker inspect 查看卷对应的宿主机目录:
docker inspect test_volume2
输出结果(部分):
[
{
"CreatedAt": "2025-09-02T12:23:35+08:00",
"Driver": "local",
"Mountpoint": "/data/var/lib/docker/volumes/test_volume2/_data",
"Name": "test_volume2",
"Scope": "local"
}
]
进入宿主机目录:
cd /data/var/lib/docker/volumes/test_volume2/_data
ls
输出结果:
50x.html index.html
3. 修改宿主机中的文件
在宿主机上修改 index.html 内容:
echo "Hello Volume -v" > index.html
cat index.html
通过浏览器访问 http://宿主机IP:5566,可以看到页面内容已更新:

4. 在容器中尝试修改文件
进入容器,尝试删除 index.html:
docker exec -it nginx2 bash
cd /usr/share/nginx/html/
rm index.html
输出结果:
rm: cannot remove 'index.html': Read-only file system
说明容器内的该目录是只读的,无法修改文件。
5. 清理释放空间
docker stop nginx2
docker rm nginx2
- 使用
-v挂载卷时,如果添加:ro参数,则表示挂载目录为 只读模式。 - 在 宿主机 上可以修改文件;但在 容器内 无法修改,保证了数据的安全性。
Docker –mount 创建管理卷
下面演示如何使用 --mount 参数创建并挂载存储卷,验证宿主机和容器的数据同步效果。
1. 使用 –mount 创建卷并启动容器
通过 --mount 指定一个新卷 test_volume3,并挂载到 Nginx 容器的 /usr/share/nginx/html 目录:
docker container run --name nginx3 -d -p 5566:80 \
--mount type=volume,source=test_volume3,target=/usr/share/nginx/html \
nginx:1.22.1
2. 查看卷是否创建成功
使用 docker volume ls 查看已创建的卷:
docker volume ls
示例输出:
DRIVER VOLUME NAME
local test_volume3
local myvoltest1
local myvoltest2
...
可以看到 test_volume3 已经在卷列表中。
3. 查看卷的挂载点
使用 docker volume inspect 查看卷对应的宿主机目录:
docker volume inspect test_volume3
输出结果(部分):
[
{
"CreatedAt": "2025-09-03T00:05:13+08:00",
"Driver": "local",
"Mountpoint": "/data/var/lib/docker/volumes/test_volume3/_data",
"Name": "test_volume3",
"Scope": "local"
}
]
4. 修改宿主机中的文件内容
进入卷目录并修改 index.html 文件:
cd /data/var/lib/docker/volumes/test_volume3/_data
echo "Hello Volume - mount" > index.html
cat index.html
输出结果:
Hello Volume - mount
此时浏览器访问 http://宿主机IP:5566,即可看到页面内容已更新:

5. 清理释放空间
实验完成后,可以停止并删除容器:
docker stop nginx3
docker rm nginx3
- 使用
--mount创建卷时,可以显式指定type、source和target,比-v更加清晰和可读。 - 卷中的数据会在宿主机和容器之间实时同步,适合持久化存储场景。
绑定卷 bind mount
绑定卷(bind mount)是将宿主机的一个目录直接挂载到容器内,与管理卷不同,它直接使用宿主机指定的目录,而不是由 Docker 自动管理。
1. 使用 -v 创建绑定卷
功能: 将宿主机目录映射到容器目录,实现数据共享。
语法:
docker run -v <宿主机目录>:<容器目录>[:options] ...
参数说明:
- 第一个参数:宿主机目录(与管理卷不同,需要手动指定路径)
- 第二个参数:容器内挂载目录
- 第三个参数(可选):挂载选项,如
ro表示只读
示例:
docker run -d -it \
--name devtest \
-v "$(pwd)"/target:/app \
nginx:latest
说明:宿主机当前目录下的 target 会挂载到容器的 /app,容器可以直接访问宿主机的文件。
2. 使用 –mount 创建绑定卷
功能: 与 -v 类似,但语法更清晰,推荐在生产环境使用。
语法:
--mount type=bind,source=<宿主机目录>,target=<容器目录>[,readonly]
关键参数:
type:bind表示绑定卷source/src:宿主机目录(与管理卷不同,需要指定路径)target/dst:容器挂载路径readonly/ro:只读挂载(可选)
示例:
docker run -d -it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
nginx:latest
说明:效果与 -v 类似,但参数更直观,适合团队协作和复杂挂载场景。
- 管理卷 (volume):由 Docker 管理,适合数据持久化和容器间共享。
- 绑定卷 (bind mount):直接使用宿主机目录,灵活,但需要手动管理路径。
- 对比来看,绑定卷更适合开发调试或访问宿主机已有数据,管理卷更适合生产环境和数据持久化。
临时卷 tmpfs
临时卷(tmpfs)是将数据存储在 内存中,不落在宿主机或容器文件系统上,因此速度非常快,但有一定局限性:
局限性
- 不同于卷和绑定卷,不能在容器之间共享 tmpfs 挂载
- 仅在 Linux 系统上运行 Docker 时可用
1. 使用 --tmpfs 创建临时卷
功能: 将容器目录映射到内存中,实现高速临时存储
语法:
--tmpfs <容器目录>
示例:
docker run -d -it \
--name tmptest \
--tmpfs /app \
nginx:1.22.1
说明:容器内的 /app 目录完全位于内存中,容器停止后数据会消失。
2. 使用 --mount 创建临时卷
功能: 与 --tmpfs 类似,但语法更灵活,可指定更多参数
语法:
--mount type=tmpfs,destination=<容器目录>[,tmpfs-size=<大小>,tmpfs-mode=<权限>]
关键参数:
type:tmpfsdestination/target:挂载到容器的目录tmpfs-size:tmpfs 容量(以字节为单位),默认无限制tmpfs-mode:文件权限(八进制),默认 1777
示例:
docker run -d -it \
--name tmptest \
--mount type=tmpfs,destination=/app \
nginx:latest
说明:/app 目录位于内存中,高速且临时,容器停止后数据会丢失。
- 临时卷 tmpfs 适合存放高速临时数据,如缓存、会话文件等
- 数据存放在内存中,容器停止或重启后会消失
- 不适合需要持久化或跨容器共享的场景
卷使用特殊注意事项
1. 普通卷(Volume)
行为说明:
- 当使用
-v或--mount指定卷名时,如果该卷已经存在,容器直接挂载这个卷。 - 如果卷不存在,Docker 会自动在管理目录下创建该卷,并将容器挂载点的初始文件内容复制到卷目录中。
- 当使用
注意点:保证卷一开始不是空的,方便数据持久化和初始化。
2. 绑定卷(Bind mount)
行为说明:
- 使用
-v指定宿主机目录不存在时,Docker 会自动创建这个目录,但目录内容为空,不会复制容器挂载点的文件。 - 使用
--mount type=bind指定不存在的宿主机目录时,会报错,需要手动创建。
- 使用
注意点:绑定卷依赖宿主机目录结构,适合直接访问宿主机已有文件。
3. 临时卷(tmpfs)
行为说明:
- 容器内挂载目录是空目录,数据完全存储在内存中。
- 容器停止或删除后,数据会完全丢失。
注意点:适合高速临时数据存储,不能持久化,也不能跨容器共享。
卷类型特殊行为总结表
| 卷类型 | 容器挂载时是否存在数据 | 宿主机目录不存在时处理 | 是否复制容器目录初始内容 | 数据持久化 | 跨容器共享 |
|---|---|---|---|---|---|
| 普通卷 Volume | 如果卷已存在,则继承 | Docker 自动创建卷 | 会复制 | 是 | 是 |
| 绑定卷 Bind | 直接使用宿主机目录 | -v:自动创建空目录 | 不会复制 | 否 | 否 |
| –mount:报错 | |||||
| 临时卷 tmpfs | 总是空目录 | 不适用 | 不适用 | 否 | 否 |
MySQL灾难恢复实验
本实验旨在验证使用Docker部署MySQL时,如何通过挂载宿主机目录实现数据的持久化存储,以及在容器异常删除后如何依旧能够完成数据恢复。
实验步骤
初始化前准备
在宿主机上创建一个空目录作为MySQL数据挂载点:mkdir -p /mydata/datadir ll /mydata/datadir此时目录下无任何文件。
运行MySQL容器并挂载目录
使用-v参数将宿主机目录挂载到容器的/var/lib/mysql路径:docker run --name mysql3 -v /mydata/datadir:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=ljx@docker -d mysql:8.0.41启动后,可以看到
/mydata/datadir目录中立即生成了MySQL系统数据库文件和相关配置。向数据库中插入数据
进入容器并操作数据库:docker exec -it mysql3 bash mysql -u root -p创建数据库和表,并插入一条数据:
create database test; use test; create table t1(name varchar(50), age int); insert into t1 values('ljx', 19); select * from t1;查询结果显示数据已成功写入。
模拟容器被异常中断和删除
模拟类似公司突然断电的情况,直接删除容器:docker stop mysql3 docker rm mysql3重新创建新容器并挂载同一目录
重新运行MySQL容器,仍挂载之前的目录:docker run --name mysql4 -v /mydata/datadir:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=ljx@docker -d mysql:8.0.41登录数据库后,发现数据依旧存在:
show databases; use test; select * from t1;可以看到之前插入的数据
('ljx', 19)仍然保留。
原理解析
为什么空目录会被写入数据?
这是因为MySQL官方镜像在启动时会检查挂载的目录是否为空。如果为空,它会自动进行初始化,将系统数据库(如mysql、sys、performance_schema)从镜像内置的模板复制到挂载目录中,以保证MySQL能够正常启动。数据持久化的原因
数据实际存储在宿主机的/mydata/datadir目录中,而不是容器内部。当容器被删除时,宿主机上的数据不会受到影响。因此,只要再次挂载同一目录,新容器就能直接读取并继续使用原有数据。
实验结论
通过本实验可以看出:
- 挂载宿主机目录是实现MySQL数据持久化的关键。
- 即使容器因故障被删除,只要数据目录未丢失,创建新的MySQL容器并挂载同一目录,即可实现数据恢复。
- 这为生产环境下的灾难恢复提供了保障,也是容器化数据库部署中必须重视的操作方式。
在实际生产环境中,仅依赖宿主机目录挂载虽然能够实现数据持久化,但仍然存在一定风险,例如:宿主机磁盘损坏、误操作删除目录、迁移时路径不一致等。因此在部署MySQL时,可以结合以下最佳实践来增强可靠性和可维护性:
优先使用Volume
Docker原生的Volume由引擎统一管理,解耦了容器与宿主机的路径关系,迁移和跨环境使用更方便。如果需要指定存储位置,可以通过Volume Driver(如NFS、Ceph、云盘插件)实现,将卷存储到独立的存储介质上。定期备份数据库
即使数据存储在持久化目录中,也难以完全避免硬件损坏、误删或勒索软件攻击。应通过mysqldump、mysqlpump或者物理备份工具(如xtrabackup)进行定期备份,并将备份文件存放到独立存储设备或远程服务器。数据与容器分离
养成“无状态化容器”的习惯,应用容器和数据存储应彻底分离。容器随时可以销毁重建,而数据应稳定存在于卷或外部存储中。多副本与高可用
在关键业务中,单节点的挂载和持久化并不足以保障数据安全。建议部署MySQL主从复制(Replication)、MGR(Group Replication)或借助Kubernetes StatefulSet,结合PV(Persistent Volume)实现多副本存储与自动恢复。
通过以上措施,可以在容器化环境中既保持MySQL的高性能和灵活性,又确保数据安全与可恢复性,从而满足生产环境对可靠性的要求。