Docker 容器数据卷
什么是容器数据卷
容器数据卷是 Docker 中用于持久化存储容器数据的一种机制。简单来说,数据卷就像是容器与宿主机之间的 “共享文件夹”
Docker 将应用与运行的环境打包形成容器运行, Docker容器产生的数据,如果不通过 docker commit 生成新的镜像,使得数据做为镜像的一部分保存下来, 那么当容器删除后,数据自然也就没有了。为了能保存数据在Docker中我们使用容器数据卷。也为了避免容器内部数据难以与外部(宿主机或其他容器)交互的问题。
卷就是目录或文件,存在于一个或多个容器中,由Docker挂载到容器,但卷不属于联合文件系统(Union FileSystem),因此能够绕过联合文件系统提供一些用于持续存储或共享数据的特性:。
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。

数据卷的相关信息
数据卷的特点:
- 数据卷可在容器之间共享或重用数据,容器可以读写数据卷中的内容,宿主机也可以直接访问这些数据
- 卷中的更改可以直接生效
- 数据卷中的更改不会包含在镜像的更新中
- 数据卷的生命周期一直持续到没有容器使用它为止
- 即使容器被删除,数据卷中的数据依然保留
数据卷的核心特性:
- 持久性:数据卷独立于容器生命周期,容器删除后数据依然保留
- 可共享性:一个数据卷可以同时被多个容器挂载
- 可重用性:数据卷可以在不同容器之间重复使用
- 高性能:数据卷直接映射到宿主机文件系统,IO 性能接近原生
- 跨平台:在不同操作系统的 Docker 环境中表现一致
Docker 提供了三种主要的数据卷类型:
类型 | 特点 | 适用场景 |
---|---|---|
命名卷(Named Volumes) | 由 Docker 管理,有唯一名称,存储在 /var/lib/docker/volumes/ | 大多数持久化存储需求,如数据库数据 |
匿名卷(Anonymous Volumes) | 由 Docker 管理,无名称,使用随机 ID 标识 | 临时数据存储,或不希望手动管理的场景 |
绑定挂载(Bind Mounts) | 将宿主机任意目录直接挂载到容器 | 需要明确指定宿主机目录的场景,如开发环境 |
数据卷的基本操作
创建命名卷
1
2# 创建一个名为myvolume的数据卷
docker volume create myvolume查看数据卷列表
1
docker volume ls
这就是本地数据卷,默认驱动,一般是
/var/lib/docker/volumes/
下对应数据卷名的目录,一长串哈希值形式的名称通常是匿名数据卷,匿名数据卷一般是在创建容器时,没显式指定数据卷名称,Docker 自动生成的(比如运行容器时用-v /容器内路径
这种简单挂载方式,没给数据卷命名,就会生成匿名卷 )。查看数据卷详情
1
docker volume inspect myvolume
挂载数据卷到容器
1
2# 将myvolume挂载到容器的/data目录
docker run -d --name mycontainer -v myvolume:/data nginx这个意思就是把名为 ,myvolume 的数据卷(如果不存在会自动创建),挂载到名为
mycontainer
容器内的/data
目录 ,实现宿主机和容器、或容器间的数据持久化 / 共享。来测试一下挂载的情况,用
docker exec -it mycontainer /bin/bash
进入容器,看看/data
目录是否存在,尝试创建个文件,然后到宿主机上查看数据卷实际路径(通过docker volume inspect myvolume
找Mountpoint
字段对应的目录 ),看看有没有test.txt
可以看到mycontain容器的myvolume数据卷的实际挂载位置中有这个目录
挂载宿主机目录(绑定挂载)
1
2
3
4# 将宿主机的/path/to/host/dir挂载到容器的/data目录
docker run -d --name mycontainer -v /path/to/host/dir:/data nginx
docker run -d --name 容器名 -v /宿主机目录:/容器内目录先创建了一个目录,然后再挂载到特定目录上
验证容器到宿主机的写入测试
1
2
3
4
5
6
7
8# 进入容器,在 /data 目录创建文件
docker exec -it mycontainer bash
# 进入容器后执行:
echo "Hello from Container" > /data/container-test.txt
exit # 退出容器
# 检查宿主机目录是否有文件
cat ~/docker-data/container-test.txt当然这个测试也可以反着来
删除数据卷
1
2
3
4
5# 删除指定数据卷
docker volume rm myvolume
# 删除所有未使用的数据卷
docker volume prune只读挂载
可以将数据卷以只读方式挂载到容器,防止容器修改数据:
1
docker run -d --name mycontainer -v myvolume:/data:ro nginx
忘删容器了,
docker rm -f mycontainer
还是换个名子吧,可以看到新建的容器的哈希id,可以看到想要修改没有权限,只读验证
可以看到输出
Hello from Host
则表示 宿主机 → 容器 读取成功(只读不影响 “读”)。1
2
3
4
5
6
7
8
9
10
11
12
13
14docker ps
docker logs mycontainer
# 进入容器,尝试在 /data 写文件
docker exec -it mycontainer bash
# 进入容器后执行:预期报错:bash: /data/test.txt: Read-only file system
echo "Try to write" > /data/test.txt
# 在宿主机数据卷目录写文件(先找数据卷路径):
# 查看 myvolume 数据卷详情
docker volume inspect myvolume
echo "Hello from Host" > /var/lib/docker/volumes/myvolume/_data/host-test.txt
# 读取文件
docker exec -it mycontainer bash
# 进入容器后执行:
cat /data/host-test.txt共享数据卷(多容器共享)
多个容器可以挂载同一个数据卷实现数据共享
1
2
3
4
5# 第一个容器挂载数据卷
docker run -d --name container1 -v sharedvolume:/data nginx
# 第二个容器挂载同一个数据卷
docker run -d --name container2 -v sharedvolume:/data nginx数据卷容器
创建专门用于共享数据的容器,其他容器通过
--volumes-from
继承其数据卷:1
2
3
4
5
6# 创建数据卷容器
docker create --name datavolume -v /data busybox
# 其他容器继承数据卷
docker run -d --name app1 --volumes-from datavolume nginx
docker run -d --name app2 --volumes-from datavolume nginx数据卷备份与恢复
1
2
3
4
5# 备份数据卷到宿主机文件
docker run --rm -v myvolume:/source -v $(pwd):/backup busybox tar -czvf /backup/volume_backup.tar.gz -C /source .
# 从备份恢复数据卷
docker run --rm -v myvolume:/target -v $(pwd):/backup busybox sh -c "tar -xzvf /backup/volume_backup.tar.gz -C /target"
容器卷 ro 和 rw 规则
Docker 支持两种主要挂载类型:
- 数据卷(Volumes):由 Docker 管理,存储在
/var/lib/docker/volumes/
目录下 - 绑定挂载(Bind Mounts):直接挂载宿主机的任意目录
无论哪种挂载类型,都可以通过 :ro
或 :rw
参数控制容器对挂载点的访问权限。
:ro
(Read-Only) 容器只能读取挂载点的数据,无法写入或修改。如果尝试写入,会抛出Read-only file system
错误。 示例:-v myvolume:/data:ro
或-v /host/path:/data:ro
:rw
(Read-Write,默认值) 容器可以自由读写挂载点的数据。如果不指定权限,默认为rw
。 示例:-v myvolume:/data
(等同于-v myvolume:/data:rw
)
权限控制是有范围的,权限仅限制容器内对挂载点的访问,不影响宿主机对原始数据的操作:
- 即使容器以
:ro
挂载,宿主机仍可自由读写数据卷或绑定目录 - 宿主机对数据的修改会实时反映到容器内(无论
ro
还是rw
)
挂载类型 | :ro 效果 |
:rw 效果 |
---|---|---|
数据卷(Volumes) | 容器无法修改 /var/lib/docker/volumes/... 中的数据 |
容器可修改数据卷中的数据 |
绑定挂载(Bind Mounts) | 容器无法修改宿主机目录中的数据 | 容器可修改宿主机目录中的数据 |
根据上面我们的测试,可以总结出来一个只读和读写的挂载测试
测试只读挂载
1 | # 创建数据卷 |
测试读写挂载
1 | # 启动容器,读写挂载(省略 :rw) |
绑定挂载的权限控制
1 | # 创建宿主机目录 |
对于绑定挂载,如果宿主机目录本身权限限制严格(如只读),即使容器以
:rw
挂载,也无法写入。
1 | # 宿主机创建只读目录 |
而且无法直接修改已运行容器的挂载权限,必须停止并重新创建容器。例如:
1 | # 错误做法:修改已运行容器的挂载权限 |
容器数据卷的继承和共享
在 Docker 中,容器卷的继承和共享是实现数据持久化和容器间协作的核心机制。
卷继承
卷继承是指新容器通过挂载已有容器的数据卷来获取其数据。这种机制允许容器间共享数据,即使原始容器已停止或删除。
如何实现卷继承,使用 --volumes-from
参数,语法
1 | docker run -d --name 新容器名 --volumes-from 已有容器名 镜像名 |
继承规则详解
- 新容器会继承源容器的所有挂载卷(包括数据卷和绑定挂载),且权限保持一致。
1 | # 创建源容器并挂载卷 |
多层继承 卷继承支持链式传递,例如:
1
A --volumes-from→ B --volumes-from→ C
此时,A 会继承 B 和 C 的所有卷。
只读 / 读写权限继承 新容器无法修改继承卷的读写权限,必须与源容器一致。例如:
1
2
3
4
5# 源容器以只读挂载
docker run -d --name source -v myvolume:/data:ro nginx
# 继承容器也只能只读访问
docker run -it --name inherit --volumes-from source alpine sh
来实际操作理解一下卷继承,粗略的步骤大概如下
1 | # 1. 创建源容器并写入数据 |
在这里以卷继承为例子,做一个完整的实验
先做一些环境准备,绑定一下挂载目录
1 | # 创建测试目录(用于绑定挂载演示) |

然后创建源容器并且写入数据
创建容器然后将命名卷挂载到容器的 /data/volume
目录,将宿主机目录挂载到容器的 /data/host
目录。from-source.txt
文件分别写入到命名卷和绑定挂载目录中。命名卷的数据存储在 Docker
内部,绑定挂载的数据直接存储在宿主机。验证ls后,容器内 ls
命令应显示两个文件,表明挂载和写入成功。
1 | # 创建源容器并挂载卷(同时使用命名卷和绑定挂载) |

然后通过卷继承创建新容器
--volumes-from source-container
让
inherit-container
继承 source-container
的所有卷配置(包括命名卷和绑定挂载)。
- 继承容器可以访问源容器写入的数据(
from-source.txt
)。 - 继承容器写入的新数据(
from-inherit.txt
)也会同步到相同卷。
验证:ls
显示两个目录下均有原有文件和新文件。cat
命令确认文件内容一致。
1 | # 创建继承容器(不直接挂载卷,而是继承 source-container 的卷) |

验证卷继承的独立性
可以看到,继承容器能访问源容器的数据,即使源容器已删除,而且继承容器写入的数据已经持久化
inherit-container
仍然可以访问卷中的数据,证明卷与容器生命周期解耦。宿主机目录
~/docker-test/host-data
中的文件与容器内一致,说明绑定挂载直接操作宿主机文件。
1 | # 停止并删除源容器(模拟故障或维护) |

清理实验的数据
1 | # 停止并删除所有容器 |
卷共享
卷共享是指多个容器直接挂载同一个数据卷,实现数据实时同步。与继承不同,共享不需要依赖特定容器。
如何实现卷共享?
命名数据卷共享 直接通过卷名挂载:
1
2
3
4
5
6
7
8# 创建命名卷
docker volume create shared_data
# 容器1挂载
docker run -d --name container1 -v shared_data:/data nginx
# 容器2挂载同一个卷
docker run -d --name container2 -v shared_data:/data mysql绑定挂载共享 多个容器挂载宿主机同一目录:
1
2
3
4
5# 容器1绑定挂载
docker run -d --name container1 -v /host/path:/data nginx
# 容器2绑定相同目录
docker run -d --name container2 -v /host/path:/data mysql共享卷会出现读写冲突,当多个容器以
rw
(读写)模式挂载同一卷时:- 文件覆盖风险:多个容器同时修改同一文件可能导致数据丢失
- 写入顺序问题:写入操作的顺序不确定,可能导致数据不一致
- 建议对共享卷进行分区(如容器 1 写
/data/logs
,容器 2 写/data/config
)
来实际操作理解一下卷共享,粗略的步骤大概如下
1 | # 1. 创建共享卷 |