网站建设服务开发,如何保护网站模板,企业门户管理系统,网页设计需要学什么书Docker 容器本身是无状态且生命周期短暂的。当一个容器被删除时#xff0c;它在可写层产生的所有数据都会随之消失。这对于需要持久化存储数据的应用 (如数据库、日志系统、用户上传内容) 来说是不可接受的。为了解决这个问题#xff0c;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 方式: typevolume,sourcevolume-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 typevolume,sourcemy-nginx-data,target/usr/share/nginx/html nginx在这两个例子中名为 my-nginx-data 的数据卷被挂载到了容器的 /usr/share/nginx/html 目录。现在你可以删除并重建 nginx-named-v 或 nginx-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 prune3. 数据卷 vs 绑定挂载
除了由 Docker 管理的数据卷Docker 还支持另一种强大的挂载方式——绑定挂载。它允许我们将宿主机上任意的一个文件或目录直接映射到容器中。
绑定挂载语法 (使用 -v)
-v /path/on/host:/path/in/container与数据卷的核心区别及选择
特性数据卷绑定挂载管理方由 Docker 管理位于 Docker 的专用存储区域 (/var/lib/docker/volumes/)。由用户管理可以是宿主机文件系统中的任意路径。可移植性高。数据卷的定义与宿主机的目录结构无关便于在不同环境中迁移。低。依赖于宿主机上特定的目录结构不易迁移。性能在 Linux 上通常性能更高因为它为数据I/O进行了优化。性能也很好但可能受宿主机文件系统权限等因素影响。权限Docker 自动处理权限。可能存在宿主机与容器内用户权限不匹配的问题。适用场景推荐用于生产环境和所有需要持久化应用数据的场景如数据库文件、应用日志等。适用于开发环境如将源代码目录挂载到容器中进行实时代码调试或共享宿主机的配置文件到容器。
代码示例直观感受数据卷与绑定挂载的行为差异
这个示例将清晰地展示数据卷独立于容器生命周期的特性以及绑定挂载下宿主机与容器的实时同步。
场景一使用数据卷的持久性演示
运行一个容器使用具名数据卷并写入数据
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 文件。
在容器内删除文件验证宿主机数据卷不受影响(为模拟容器内误操作)
docker exec vol-test-container rm /data/message.txt验证容器内文件已删除
docker exec vol-test-container ls /data(此时应无输出) 关键点此时 my-persistent-data 这个数据卷本身在宿主机上仍然包含 message.txt 文件。容器的删除操作仅仅是在容器的可写层记录了“该文件已删除”的标记并未真正删除数据卷中的源文件。 删除容器然后创建一个新容器挂载同一个数据卷
docker stop vol-test-container
docker rm vol-test-container# 创建一个全新的容器挂载之前的数据卷
docker run --name vol-test-checker -it -v my-persistent-data:/data ubuntu在新容器中查看数据 当你进入 vol-test-checker 容器的交互式终端后查看 /data 目录
# 在 vol-test-checker 容器的shell中执行
ls /data
# 输出应为message.txtcat /data/message.txt
# 输出应为This data is in a volume结论这个实验有力地证明了数据卷中的数据是独立且持久的。即使容器内的文件被看似“删除”或者整个容器被删除数据卷中的原始数据也安然无恙可以被新的容器重新挂载和使用。 场景二使用绑定挂载的实时同步演示
在宿主机上创建一个目录和文件
mkdir -p ./host-data
echo Initial data from host ./host-data/sync.txt运行一个容器将宿主机目录绑定挂载到容器中
docker run -d --name bind-test-container -v $(pwd)/host-data:/data ubuntu tail -f /dev/nulltail -f /dev/null 是一个让容器保持运行的技巧。现在宿主机的 ./host-data 目录与容器的 /data 目录实时同步。 3. 验证容器内可以看到宿主机文件
docker exec bind-test-container cat /data/sync.txt
# 输出应为Initial data from host4. 在宿主机上修改文件内容
echo Host updated the file ./host-data/sync.txt在容器内立即查看变化
docker exec bind-test-container cat /data/sync.txt
# 输出现在应包含两行
# Initial data from host
# Host updated the file在容器内删除文件
docker exec bind-test-container rm /data/sync.txt在宿主机上验证文件是否也被删除
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_PASSWORD123456 \
--mount typevolume,sourcemysql-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。
步骤三验证数据持久化
进入容器并创建数据 使用 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;主机也能正常连接上
删除容器 现在我们模拟一次容器故障或升级删除这个 MySQL 容器。
docker stop my-mysql
docker rm my-mysql此时容器已经不存在了。
重新创建容器挂载同一个数据卷 我们再次运行一个 MySQL 容器使用相同的命令确保它挂载的还是 mysql-data 这个数据卷。
docker run -d \
--name my-mysql-new \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORDmysecretpassword \
--mount typevolume,sourcemysql-data,target/var/lib/mysql \
mysql:5.7验证数据是否恢复 等待新容器 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-redis 的 redis 容器并使用 -v 标志将一个名为 redis-data 的具名数据卷挂载到容器的 /data 目录。
题目四具名挂载 (使用 --mount) 使用 --mount 标志重写上一题的命令实现完全相同的效果。
题目五绑定挂载 写出一条命令运行一个临时的、交互式的 alpine 容器并将宿主机当前目录下的 app 子目录 (假设为 ./app) 绑定挂载到容器的 /app 目录。容器启动后执行 ls /app 命令。
题目六数据共享
首先运行一个名为 writer-container 的 busybox 容器将一个名为 shared-volume 的数据卷挂载到 /shared。容器启动后向 /shared/message.txt 文件写入 “Hello from writer”。然后运行另一个名为 reader-container 的 busybox 容器同样挂载 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 typevolume,sourceredis-data,target/data redis解析 --mount 标志使用更明确的键值对语法。typevolume 指定类型source 指定数据卷名称target 指定容器内路径。 答案五
docker run --rm -it --mount typebind,source$(pwd)/app,target/app alpine ls /app解析 --mount typebind 指定了绑定挂载。source$(pwd)/app 表示宿主机当前工作目录下的 app 目录。--rm 使容器退出后自动删除-it 提供交互式终端。容器启动后直接执行 ls /app 命令。 答案六
运行 writer-container
docker run --name writer-container -v shared-volume:/shared busybox sh -c echo Hello from writer /shared/message.txt运行 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 typevolume,sourcemysql-data,target/dbdata,readonly \
--mount typebind,source/backup,target/backup_host \
ubuntu \
tar czvf /backup_host/mysql-backup-$(date %Y%m%d).tar.gz -C /dbdata .日期2025年9月5日 专栏Docker教程