五、Docker 核心技术:容器数据持久化之数据卷

Docker 容器本身是无状态且生命周期短暂的。当一个容器被删除时,它在可写层产生的所有数据都会随之消失。这对于需要持久化存储数据的应用 (如数据库、日志系统、用户上传内容) 来说是不可接受的。为了解决这个问题,Docker 提供了多种数据持久化方案,其中最重要、最推荐的就是数据卷

一、什么是容器数据卷

数据卷宿主机文件系统中一个特殊的目录,它由 Docker 管理 (/var/lib/docker/volumes/ 目录下),并可以直接映射一个或多个容器的指定目录下。

数据卷的核心优势:

数据持久化:数据卷的生命周期独立于任何容器。即使所有使用该数据卷的容器都被删除,数据卷及其中的数据依然存在
数据共享多个容器可以同时挂载同一个数据卷,从而实现容器间的数据共享和同步
高性能:数据卷绕过了容器的联合文件系统 (UnionFS),直接读写宿主机的文件系统,具有接近原生的I/O性能。
易于管理:Docker 提供了专门的命令 (docker volume ...) 来创建、查看、删除数据卷,便于备份、迁移和恢复

二、数据卷的使用

创建或运行容器时,我们主要使用 -v--mount 标志来挂载数据卷-v 语法更简洁--mount 语法更明确推荐在生产环境和复杂场景下使用 --mount

1. 匿名挂载

如果你在 -v 标志中只指定容器内的路径,Docker 会自动创建一个匿名的数据卷,并将其挂载到该路径。

语法:

-v /path/in/container

代码案例:

docker run -d -P --name nginx-anon -v /usr/share/nginx/html nginx
  • 这个命令会创建一个新的、名字是随机哈希值的数据卷,并挂载到容器的 /usr/share/nginx/html 目录。
  • 我们可以通过 docker inspect 查看这个匿名数据卷具体信息
docker inspect nginx-anon

在这里插入图片描述

在输出的 "Mounts" 部分,你会看到类似这样的信息:

"Mounts": [{"Type": "volume","Name": "a1b2c3d4...", // 随机生成的长哈希值"Source": "/var/lib/docker/volumes/a1b2c3d4.../_data","Destination": "/usr/share/nginx/html",...}
]

在这里插入图片描述

  • 缺点:匿名挂载的数据卷名称不直观,难以管理和复用

2.具名挂载

这是最推荐的数据卷使用方式。你可以为数据卷指定一个有意义的名称,方便后续的引用、共享和管理

语法:

-v 方式: volume-name:/path/in/container
--mount 方式: type=volume,source=volume-name,target=/path/in/container

代码案例:

步骤一:创建具名数据卷 (可选,Docker会在挂载时自动创建)

docker volume create my-nginx-data

步骤二:使用具名数据卷运行容器

  • 使用 -v 标志:
docker run -d -P --name nginx-named-v -v my-nginx-data:/usr/share/nginx/html nginx
  • 使用 --mount 标志 (推荐):
docker run -d -P --name nginx-named-mount --mount type=volume,source=my-nginx-data,target=/usr/share/nginx/html nginx
  • 在这两个例子中,名为 my-nginx-data数据卷挂载到了容器的 /usr/share/nginx/html 目录。
  • 现在,你可以删除并重建 nginx-named-vnginx-named-mount 容器,但只要重新挂载 my-nginx-data 数据卷,网站的数据 (如 index.html) 就会保持不变

数据卷管理命令:

# 列出所有数据卷
docker volume ls# 查看某个数据卷的详细信息
docker volume inspect my-nginx-data# 删除一个数据卷 (前提是没有容器正在使用它)
docker volume rm my-nginx-data# 删除所有不再被任何容器使用的悬空数据卷 (dangling volumes)
docker volume prune

在这里插入图片描述
在这里插入图片描述

3. 数据卷 vs 绑定挂载

除了由 Docker 管理的数据卷,Docker 还支持另一种强大的挂载方式——绑定挂载。它允许我们将宿主机上任意的一个文件或目录直接映射到容器中。

绑定挂载语法 (使用 -v):

-v /path/on/host:/path/in/container

与数据卷的核心区别及选择:

特性数据卷绑定挂载
管理方由 Docker 管理,位于 Docker 的专用存储区域 (/var/lib/docker/volumes/)。由用户管理,可以是宿主机文件系统中的任意路径
可移植性。数据卷的定义与宿主机的目录结构无关,便于在不同环境中迁移。。依赖于宿主机上特定的目录结构,不易迁移。
性能在 Linux 上通常性能更高,因为它为数据I/O进行了优化。性能也很好,但可能受宿主机文件系统权限等因素影响。
权限Docker 自动处理权限。可能存在宿主机与容器内用户权限不匹配的问题。
适用场景推荐用于生产环境和所有需要持久化应用数据的场景,如数据库文件、应用日志等。适用于开发环境,如将源代码目录挂载到容器中进行实时代码调试;或共享宿主机配置文件到容器。

代码示例:直观感受数据卷与绑定挂载的行为差异

这个示例将清晰地展示数据卷独立于容器生命周期的特性,以及绑定挂载下宿主机与容器实时同步

场景一:使用数据卷的持久性演示

  1. 运行一个容器,使用具名数据卷并写入数据:
docker run -d --name vol-test-container -v my-persistent-data:/data ubuntu sleep infinity
docker exec vol-test-container sh -c "echo 'This data is in a volume' > /data/message.txt"

在这里插入图片描述

  • 此时,名为 my-persistent-data 的数据卷中已经包含了 message.txt 文件。
  1. 在容器内删除文件,验证宿主机数据卷不受影响:(为模拟容器内误操作)
docker exec vol-test-container rm /data/message.txt

验证容器内文件已删除

docker exec vol-test-container ls /data

在这里插入图片描述

(此时应无输出)

关键点:此时 my-persistent-data 这个数据卷本身在宿主机上仍然包含 message.txt 文件。容器的删除操作仅仅是在容器的可写层记录了“该文件已删除”的标记并未真正删除数据卷中的源文件。

  1. 删除容器,然后创建一个新容器挂载同一个数据卷:
docker stop vol-test-container
docker rm vol-test-container# 创建一个全新的容器,挂载之前的数据卷
docker run --name vol-test-checker -it -v my-persistent-data:/data ubuntu
  1. 在新容器中查看数据:
    当你进入 vol-test-checker 容器的交互式终端后,查看 /data 目录:
# 在 vol-test-checker 容器的shell中执行
ls /data
# 输出应为:message.txtcat /data/message.txt
# 输出应为:This data is in a volume

结论:这个实验有力地证明了,数据卷中的数据是独立且持久的。即使容器内的文件被看似“删除”,或者整个容器删除,数据卷中的原始数据安然无恙,可以被新的容器重新挂载和使用。

场景二:使用绑定挂载的实时同步演示

  1. 在宿主机上创建一个目录和文件:
mkdir -p ./host-data
echo "Initial data from host" > ./host-data/sync.txt
  1. 运行一个容器,将宿主机目录绑定挂载到容器中:
docker run -d --name bind-test-container -v $(pwd)/host-data:/data ubuntu tail -f /dev/null
  • tail -f /dev/null 是一个让容器保持运行的技巧。
  • 现在,宿主机的 ./host-data 目录与容器的 /data 目录实时同步

在这里插入图片描述
3. 验证容器内可以看到宿主机文件:

docker exec bind-test-container cat /data/sync.txt
# 输出应为:Initial data from host

在这里插入图片描述
4. 宿主机上修改文件内容:

echo "Host updated the file" >> ./host-data/sync.txt
  1. 容器内立即查看变化:
docker exec bind-test-container cat /data/sync.txt
# 输出现在应包含两行:
# Initial data from host
# Host updated the file

在这里插入图片描述

  1. 容器内删除文件:
docker exec bind-test-container rm /data/sync.txt
  1. 宿主机上验证文件是否也被删除:
ls ./host-data/
# (此时应无输出,文件已被删除)

在这里插入图片描述

结论:绑定挂载建立了宿主机和容器之间文件系统的直接链接。任何一方对挂载目录中内容的修改或删除,都会立即、真实地反映在另一方。这种实时同步的特性使其非常适合开发时共享源代码

4. 综合案例:使用具名数据卷持久化 MySQL 数据

这个案例将演示如何创建一个 MySQL 容器,并将其数据目录 /var/lib/mysql 持久化到一个具名数据卷中,从而实现数据库数据的安全存储

步骤一:创建具名数据卷
为了清晰管理,我们先创建一个名为 mysql-data 的数据卷。

docker volume create mysql-data

步骤二:运行 MySQL 容器并挂载数据卷
我们将运行一个 MySQL 8.0 容器,并设置 root 密码

docker run -d \
--name my-mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
--mount type=volume,source=mysql-data,target=/var/lib/mysql \
mysql:8.0
  • -d: 后台运行容器。
  • --name my-mysql: 为容器命名。
  • -p 3306:3306: 将宿主机的 3306 端口映射到容器的 3306 端口。
  • -e MYSQL_ROOT_PASSWORD=...: 通过环境变量设置 MySQL 的 root 用户密码。
  • --mount ...: 核心部分。将我们创建的 mysql-data 数据卷挂载到容器内部存放数据库文件标准路径 /var/lib/mysql

步骤三:验证数据持久化

  1. 进入容器并创建数据
    使用 docker exec 进入正在运行的 MySQL 容器,并登录到数据库。
docker exec -it my-mysql mysql -uroot -pmysecretpassword

在 MySQL 命令行中,创建一个新的数据库和表,并插入一些数据

CREATE DATABASE testdb;
USE testdb;
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');
EXIT;

在这里插入图片描述
主机也能正常连接上
在这里插入图片描述

  1. 删除容器
    现在,我们模拟一次容器故障或升级删除这个 MySQL 容器。
docker stop my-mysql
docker rm my-mysql

此时,容器已经不存在了。

  1. 重新创建容器,挂载同一个数据卷
    我们再次运行一个 MySQL 容器,使用相同的命令,确保它挂载的还是 mysql-data 这个数据卷。
docker run -d \
--name my-mysql-new \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=mysecretpassword \
--mount type=volume,source=mysql-data,target=/var/lib/mysql \
mysql:5.7
  1. 验证数据是否恢复
    等待新容器 my-mysql-new 完全启动后,再次进入这个新容器。
docker exec -it my-mysql-new mysql -uroot -pmysecretpassword

在 MySQL 命令行中,检查我们之前创建的数据库和数据是否存在。

USE testdb;
SELECT * FROM users;

你会看到输出

+----+-------+
| id | name  |
+----+-------+
|  1 | Alice |
|  2 | Bob   |
+----+-------+

证明了,即使容器被删除存储在数据卷中的数据被完美地保留了下来,并在新容器得以恢复

总结: 容器数据卷是实现Docker数据持久化首选方案。通过使用具名数据卷,我们可以安全地存储应用数据解耦数据与容器的生命周期,并轻松实现数据的共享、备份和恢复,为在生产环境运行有状态应用提供了坚实的基础


练习题

题目一:创建与查看数据卷
写出一条命令,创建一个名为 app-config 的具名数据卷,然后写出另一条命令来查看这个数据卷的详细信息。

题目二:匿名挂载
写出一条命令,以后台模式运行一个 ubuntu 容器,并为容器内的 /data 目录进行匿名挂载。

题目三:具名挂载 (使用 -v)
写出一条命令,以后台模式运行一个名为 my-redisredis 容器,并使用 -v 标志将一个名为 redis-data 的具名数据卷挂载到容器的 /data 目录。

题目四:具名挂载 (使用 --mount)
使用 --mount 标志重写上一题的命令,实现完全相同的效果。

题目五:绑定挂载
写出一条命令,运行一个临时的、交互式的 alpine 容器,并将宿主机当前目录下的 app 子目录 (假设为 ./app) 绑定挂载到容器的 /app 目录。容器启动后执行 ls /app 命令。

题目六:数据共享

  1. 首先,运行一个名为 writer-containerbusybox 容器,将一个名为 shared-volume 的数据卷挂载到 /shared。容器启动后,向 /shared/message.txt 文件写入 “Hello from writer”。
  2. 然后,运行另一个名为 reader-containerbusybox 容器,同样挂载 shared-volume 数据卷到 /shared,并读取 /shared/message.txt 文件的内容。
    (请分别写出这两个 docker run 命令)

题目七:数据卷清理
写出一条命令,可以一次性删除所有当前未被任何容器使用的Docker数据卷。

题目八:数据卷数据备份
假设 mysql-data 数据卷中包含了重要的数据库文件,你希望对其进行备份。请描述一种简单的、利用另一个临时容器来备份该数据卷中所有文件到宿主机 /backup 目录的思路或命令。

答案与解析

答案一:
创建数据卷:

docker volume create app-config

查看详细信息:

docker volume inspect app-config

解析: docker volume create 用于创建具名数据卷,docker volume inspect 用于查看其元数据,包括在宿主机上的实际存储路径。

答案二:

docker run -d --name ubuntu-anon -v /data ubuntu

解析: -v 标志后只跟了容器内的路径 /data,这会触发Docker创建一个匿名数据卷并挂载到此路径。

答案三:

docker run -d --name my-redis -v redis-data:/data redis

解析: -v 标志使用 [volume_name]:[container_path] 的格式来进行具名挂载。如果 redis-data 数据卷不存在,Docker会自动创建它。

答案四:

docker run -d --name my-redis --mount type=volume,source=redis-data,target=/data redis

解析: --mount 标志使用更明确的键值对语法。type=volume 指定类型,source 指定数据卷名称,target 指定容器内路径。

答案五:

docker run --rm -it --mount type=bind,source=$(pwd)/app,target=/app alpine ls /app

解析: --mount type=bind 指定了绑定挂载。source=$(pwd)/app 表示宿主机当前工作目录下的 app 目录。--rm 使容器退出后自动删除,-it 提供交互式终端。容器启动后直接执行 ls /app 命令。

答案六:

  1. 运行 writer-container
docker run --name writer-container -v shared-volume:/shared busybox sh -c "echo 'Hello from writer' > /shared/message.txt"
  1. 运行 reader-container
docker run --name reader-container -v shared-volume:/shared busybox cat /shared/message.txt

解析: 两个容器都挂载了同一个具名数据卷 shared-volume。第一个容器向卷中写入文件,第二个容器可以立即读取到这个文件,实现了数据共享。

答案七:

docker volume prune

解析: docker volume prune 是一个方便的命令,用于清理不再被任何(包括已停止的)容器引用的数据卷,可以释放磁盘空间。

答案八:

docker run --rm \
--mount type=volume,source=mysql-data,target=/dbdata,readonly \
--mount type=bind,source=/backup,target=/backup_host \
ubuntu \
tar czvf /backup_host/mysql-backup-$(date +%Y%m%d).tar.gz -C /dbdata .

在这里插入图片描述

日期:2025年9月5日
专栏:Docker教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/921372.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/921372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端视觉交互设计全解析:从悬停高亮到多维交互体系(含代码 + 图表)

在前端用户体验领域,视觉交互是连接用户与产品的 “隐形桥梁”—— 它通过可视化信号传递操作意图、反馈系统状态,直接决定用户对产品的感知。很多开发者对视觉交互的认知停留在 “鼠标悬停高亮”,但实际上,视觉交互是一个覆盖 “…

从零打造商业级LLMOps平台:开源项目LMForge详解,助力多模型AI Agent开发!

最近,我发现了一个超级实用的开源项目——LMForge-End-to-End-LLMOps-Platform-for-Multi-Model-Agents(以下简称LMForge)。这个项目是一个端到端的LLMOps(Large Language Model Operations)平台,专为多模型…

【C++练习】06.输出100以内的所有素数

目录输出100以内的所有素数方法1:基础判断法方法2:埃拉托斯特尼筛法(效率更高)方法3:优化版筛法(只考虑奇数)方法4:使用STL算法方法5:递归实现总结: 输出100以…

在开发中使用git rebase的场景

rebase介绍 一、背景 远程仓库有oh4w-dev和oh4k-dev两个分支,oh4k-dev是基于oh4w-dev开发到80%的代码新拉的分支;此后两条分支同步开发,当oh4k-dev开发完成,oh4w-dev还在开发阶段,oh4k-dev需要拉取到oh4w-dev自分出o…

TDengine 时序函数 NOW() 用户手册

TDengine NOW() 函数用户使用手册 目录 功能概述函数语法返回值说明技术特性使用场景及示例时间运算操作注意事项常见问题 功能概述 NOW() 函数是 TDengine 中的时间函数,用于获取客户端当前系统时间。该函数在时序数据库中特别有用,可以用于数据插入…

JavaWeb ——事务管理

文章目录事务管理事务回顾Spring事务管理事务进阶事务属性 - 回滚 rollbackFor事务属性 - 传播行为 propagationSpring框架第一大核心: IOC控制反转, 其第二大核心就是 AOP 面向切面编程 事务管理 事务回顾 Spring事务管理 # spring 事务管理日志 logging:level:org…

【跨国数仓迁移最佳实践8】MaxCompute Streaming Insert: 大数据数据流写业务迁移的实践与突破

本系列文章将围绕东南亚头部科技集团的真实迁移历程展开,逐步拆解 BigQuery 迁移至 MaxCompute 过程中的关键挑战与技术创新。本篇为第八篇,MaxCompute Streaming Insert: 大数据数据流写业务迁移的实践与突破。注:客户背景为东南…

2025-09-05 CSS4——浮动与定位

文章目录1 显示(Display)1.1 visibility:hidden1.2 display:none2 块和内联元素2.1 块元素2.2 内联元素2.3 改变元素的显示方式3 浮动(Float)3.1 float 属性3.2 clear 属性4 定位(Position)4.1 五种定位模式…

43这周打卡——生成手势图像 (可控制生成)

目录 前言 1.导入数据及数据可视化 2.构建模型 3.训练模型 4.模型分析并生成指定图像 总结 前言 🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊 1.导入数据及数据可视化 from torchvision import data…

TDengine 时间函数 TIMEDIFF() 用户手册

TDengine TIMEDIFF() 函数详细使用手册 目录 功能概述函数语法参数说明返回值说明版本变更说明技术特性使用场景及示例时间单位处理数据类型兼容性注意事项常见问题最佳实践 功能概述 TIMEDIFF() 函数用于计算两个时间戳的差值,返回 expr1 - expr2 的结果。结果…

【2025ICCV-持续学习方向】一种用于提示持续学习(Prompt-based Continual Learning, PCL)的新方法

1. 背景与问题 (Background & Problem):​​ ​持续学习 (CL):​​ 目标是在不遗忘旧任务知识的情况下,让模型持续学习一系列新任务。主要挑战是灾难性遗忘。 ​基于提示的持续学习 (PCL):​​ 利用预训练视觉Transformer (ViT),冻结其权重,通过微调称为“提示”(prompt…

2025 年 08 月 GitHub 十大热门项目排行榜

欢迎来到 2025 年 8 月 GitHub 热门开源项目排行榜!本月榜单集中展示了来自智能体平台、AI 编程助手、多模态角色系统、本地化部署工具到可视化白板与企业协同平台的多元创新。从构建 AI 助手中枢的 Archon,到终端 AI 编码拍档 Crush,再到虚拟…

LeetCode每日一题,2025-9-4

多数元素 投票法 让你找到序列中出现超过二分之一的元素,一定要记住这个规则。 记录两个值val和cnt,刚开始val为任意数,cnt0。 如果cnt是0,就把当前val num。接下来判断,ifnum val,则cnt ,e…

第7章 安全配置

7.1 安全概述 Jenkins安全威胁 常见安全风险: 访问控制风险: - 未授权访问Jenkins实例 - 权限提升攻击 - 横向移动攻击 - 敏感信息泄露代码执行风险: - 恶意脚本注入 - 构建脚本篡改 - 插件漏洞利用 - 远程代码执行数据安全风险: …

腾讯混元世界模型Voyager开源:单图生成3D世界的“核弹级”突破,游戏、VR、自动驾驶迎来新变量

当AI绘画、视频生成技术逐渐从“新鲜感”走向“实用化”,3D内容生成却始终卡在“效率低、成本高、门槛高”的瓶颈里。传统3D建模需要专业软件、大量人工调整,甚至依赖昂贵的硬件设备,让中小团队和个人创作者望而却步。 但腾讯AI实验室最近开…

数据库(基础操作)

SQL 结构化的查询语句 我们现在需要写SQL语句 --- 这个玩意儿就是数据库的操作语句我们的数据库就类似于一个excl表格它有n列,每一列为一个大类,数据以行存在,一行代表一个条目数据如:我现在想建立一个数据库保存学生的信息你需要…

linux ubi文件系统

1,UBI(Unsorted Block Images)是 Linux 内核中为原始 Flash 设备提供的一种抽象层,位于 MTD(Memory Technology Device)和文件系统(如 UBIFS)之间。它负责坏块管理、磨损均衡、逻辑卷…

深度厚金板PCB与厚铜PCB的区别

厚金板PCB和厚铜PCB在电子制造领域都有重要应用,它们有着不同的特点和适用场景。下面为你详细介绍二者的区别。厚金PCB是什么厚金PCB是在印制电路板表面镀上较厚金层的电路板。这层厚金能提升电路板的导电性、抗氧化性和耐磨性。在一些对信号传输要求极高、使用环境…

一阶低通滤波器应用示例(演示)

1. 代码 这段代码实现了一个一阶低通滤波器(也称为指数加权移动平均滤波器)。它适用于需要平滑数据、减少噪声的场合。以下是一些常见的应用场景: 传感器数据平滑:在嵌入式系统或物联网设备中,传感器(如温度…

RT-Thread源码分析字节实现socket源码

无论是客户端还是服务器程序,发送的底层都是发送AT指令:1)发送命令到串口;2)阻塞等待返回结果接收的底层都是1)阻塞等待;2)被唤醒后拷贝处理数据两者均由后台任务唤醒,后…