Docker 存储是容器化应用中数据持久化的关键部分,它解决了容器生命周期与数据生命周期不一致的问题。
1、概念
Docker 提供了两种主要的存储资源类型:
1.1 由 Storage Driver
管理的存储
用于管理容器运行时产生的临时数据 。容器由最顶层的可写容器层和下面的只读镜像层组成。这种分层结构依赖于 写时复制(Copy-on-Write
, CoW) 机制。任何对现有文件的修改都会从只读层复制到可写层后进行,因此性能通常不如数据卷,且容器删除后数据会丢失。
1.2 Data Volume(数据卷)
这是 Docker 提供的持久化存储数据的方法,数据卷是宿主机文件系统中的目录或文件,能够直接被挂载到容器的文件系统中。其生命周期独立于容器,即使容器被删除,数据卷也会保留。对数据卷的修改会立刻生效,并且不会影响镜像
2、存储驱动(Storage Driver)
存储驱动负责管理 Docker 镜像层和容器可写层的底层技术,是实现 CoW
的关键
常用的存储驱动:
- overlay2(推荐)
Docker 默认 的存储驱动
基于 Linux 内核的 overlay/overlay2 联合文件系统
性能优秀,支持页缓存共享
所需磁盘空间较少 - devicemapper
适用于不支持 overlay2 的 Linux 发行版
基于块设备而非文件系统
支持 thin provisioning(瘦供给) - btrfs 和 zfs
适用于有高级存储需求的场景
提供优秀的快照和克隆功能
适合大规模部署 - aufs
Docker 早期使用的驱动,在某些旧系统(如 Ubuntu 14.04)上可能仍是默认选项
查看和配置存储驱动:
bash
# 查看当前使用的存储驱动
docker info | grep "Storage Driver"
# 配置存储驱动(需修改 /etc/docker/daemon.json)
{
"storage-driver": "overlay2"
}
3、Docker 数据持久化
3.1 Volumes(数据卷) - 推荐方式
数据卷是 Docker 管理的宿主机文件系统的一部分(默认位于 /var/lib/docker/volumes/
),是持久化和共享数据的最佳方式。
特点:
- 由 Docker 管理,与宿主机的核心功能隔离
- 可以命名和重用
- 容器删除后数据仍然保留
- 多个容器可以共享同一个卷
- 可以通过 docker volume 命令管理
常用命令:
bash
# 创建一个名为 my-vol 的数据卷
docker volume create my-vol
# 查看所有数据卷
docker volume ls
# 查看数据卷的详细信息(包括在宿主机上的具体路径)
docker volume inspect my-vol
# 输出会显示 "Mountpoint": "/var/lib/docker/volumes/my-vol/_data"
# 删除一个数据卷(需确保没有容器正在使用它)
docker volume rm my-vol
# 删除所有未被使用的数据卷(清理空间)
docker volume prune
# 使用 --mount 标志(推荐,语法更清晰)
docker run -d --name my-container \
--mount source=my-volume,target=/app/data \
my-image
# 或使用 -v 标志(传统方式)
docker run -d --name my-container \
-v my-volume:/app/data \
my-image
3.2 Bind Mounts(绑定挂载)
绑定挂载提供了更高的灵活性,但也将容器与宿主机的目录结构紧密耦合。
特点:
- 可以挂载宿主机的任何文件或目录
- 性能优秀
- 宿主机和容器可以共享文件修改
- 不便于移植(依赖宿主机的文件系统结构)
适用场景:
- 在宿主机和容器之间共享配置文件(如将宿主机的
nginx.conf
挂载到容器的/etc/nginx/nginx.conf
)。 - 在开发环境中,将宿主机的源代码目录挂载到容器中,实现代码的实时同步和测试。
常用命令:
bash
# 假设你的项目代码在宿主机的 /home/user/myapp 目录
# 将其挂载到容器的 /app 目录
docker run -it --rm \
--name dev-container \
-v /home/user/myapp:/app \ # 使用宿主机绝对路径
-p 3000:3000 \
node:16-alpine \
sh
# 现在,你在宿主机上修改代码,容器内的 /app 目录会立即更新。
# 反之,在容器内 /app 创建的文件,也会出现在宿主机的 /home/user/myapp 中。
注意:
- 使用 -v 时,如果源是绝对路径 (如 /home/user/data),Docker 会认为是
Bind Mount
。 - 如果源不是绝对路径(如 myvolume),Docker 会认为是
Volume
。
3.3 Tmpfs Mounts(临时文件系统)
用于存储不需要持久化的敏感临时数据,如临时会话文件、缓存等。
特点:
- 数据存储在内存中,访问速度快
- 容器停止后数据丢失
- 适合存储临时数据或敏感信息
- 可以限制大小
常用命令:
bash
docker run -it --rm \
--name tmpfs-container \
--tmpfs /app/cache \
alpine:latest sh
# 在容器内向 /app/cache 写入的数据,只存在于内存中。
# 限制tmpfs大小(100MB)
docker run -d \
--name=app \
--tmpfs /tmp:size=100m \
nginx
4、多容器共享数据
4.1 通过数据卷共享
多个容器通过数据卷共享数据
bash
# 创建共享数据卷
docker volume create shared-data
# 启动第一个容器,写入数据到共享卷
docker run -d \
--name=writer \
-v shared-data:/data \
alpine \
sh -c "echo 'Hello from writer' > /data/message.txt && sleep 3600"
# 启动第二个容器,读取共享卷中的数据
docker run -it \
--name=reader \
-v shared-data:/data \
alpine \
cat /data/message.txt
# 启动第三个容器,追加数据到共享卷
docker run -it \
--name=appender \
-v shared-data:/data \
alpine \
sh -c "echo 'Hello from appender' >> /data/message.txt && cat /data/message.txt"
4.2 通过数据卷容器
创建一个专门用于提供数据卷的容器,其他容器通过 --volumes-from来共享其数据卷
bash
# 创建一个数据卷容器(通常使用简单镜像如 busybox)
docker create -v /shared-data --name data-container busybox
# 其他容器使用 --volumes-from 挂载数据卷容器中的卷
docker run --volumes-from data-container --name app1 my-image
docker run --volumes-from data-container --name app2 my-image