【Docker】Docker数据卷管理及优化

Docker 数据卷是一个可供容器使用的特殊目录,它绕过了容器的文件系统,直接将数据存储在宿主机上。
这样可以实现以下几个重要的目的:
-
数据持久化:即使容器被删除或重新创建,数据卷中的数据仍然存在,不会丢失。
-
数据共享:多个容器可以同时挂载同一个数据卷,实现数据的共享和交互。
-
独立于容器生命周期:数据卷的生命周期独立于容器,不受容器的启动、停止和删除的影响。
一、数据卷简介
1.1 引言
docker的镜像是由多个只读的文件系统叠加在一起形成的。当我们在我启动一个容器的时候,docker会加载这些只读层并在这些只读层的上面(栈顶)增加一个读写层。这时如果修改正在运行的容器中已有的文件,那么这个文件将会从只读层复制到读写层。该文件的只读版本还在,只是被上面读写层的该文件的副本隐藏。当删除docker,或者重新启动时,之前的更改将会消失。在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统)。
为了很好的实现数据保存和数据共享,Docker提出了Volume这个概念,简单的说就是绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。又被称作数据卷。
1.2 什么是数据卷
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性: - 数据卷可以在容器之间共享和重用 - 对数据卷的修改会立马生效 - 对数据卷的更新,不会影响镜像 - 数据卷默认会一直存在,即使容器被删除 Docker中提供了两种挂载方式,-v和-mount
1.3 为什么使用数据卷
Docker的镜像是由一系列的只读层组合而来,当启动一个容器的时候,Docker加载镜像的所有只读层,并在最上层加入一个读写层。这个设计使得Docker可以提高镜像构建、存储和分发的效率,节省了时间和存储空间,然而也存在如下问题。
-
容器中的文件在宿主机上存在形式复杂,不能在宿主机上很方便的对容器中的文件进行访问
-
多个容器之间的数据无法共享
-
当删除容器时,容器产生的数据将丢失
为了解决这些问题,Docker引入了数据卷(volume)机制。volume是存在一个或多个容器中的特定文件或文件夹,这个目录能够独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久提供一下便利。
-
volume在容器创建时就初始化,在容器运行时就可以使用其中的文件
-
volume能在不同的容器之间共享和重用
-
对volume中的数据的操作会马上生效
-
对volume中数据操作不会影响到镜像本身
-
volume的生存周期独立于容器的生存周期,即使删除容器,volume仍然会存在,没有任何容器使用的volume也不会被Docker删除
docker提供了两种卷:
-
bind mount
-
docker managed volume
二、bind mount 数据卷
-
是将主机上的目录或文件mount到容器里。
-
使用直观高效,易于理解。
-
使用 -v 选项指定路径,格式 <host path>:<container path>
-
-v选项指定的路径,如果不存在,挂载时会自动创建
2.1 示例
[root@docker ~]# docker run -it --rm \
-v /tmp/data1:/data1 \
-v /tmp/data1:/data2:ro \ # 指定/data2目录为只读属性
-v /etc/passwd:/data/passwd:ro \ # 指定/data/passwd文件为只读属性
busybox
/ # tail -n 3 /data/passwd
lee:x:1000:1000:lee:/home/lee:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
nginx:x:1001:1001::/home/nginx:/sbin/nologin
/ # touch /data1/leefile1
/ # touch /data2/leefile1 # 尝试在/data目录创建文件,但是被拒绝
touch: /data2/leefile1: Read-only file system
三、docker manager 数据卷
-
bind mount必须指定host文件系统路径,限制了移植性
-
docker managed volume 不需要指定mount源,docker自动为容器创建数据卷目录
-
默认创建的数据卷目录都在 /var/lib/docker/volumes 中
-
如果挂载时指向容器内已有的目录,原有数据会被复制到volume中
3.1 示例
# 运行mysql容器
[root@docker volumes]# docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123' mysql:5.7
# 查看mysql容器的数据卷
[root@docker volumes]# ls -l /var/lib/docker/volumes
总用量 0
drwx-----x 3 root root 19 8月 20 16:34 ad74662b8d6bb6fdcc6e82925ae9942b94bac5f9da4bd52b0a14ac451ae9ef75
# 在数据卷下创建文件
[root@docker volumes]# touch ad74662b8d6bb6fdcc6e82925ae9942b94bac5f9da4bd52b0a14ac451ae9ef75/_data/leefile
# 进入容器查看文件是否存在
[root@docker volumes]# docker exec -it mysql bash
bash-4.2# cd /var/lib/mysql
bash-4.2# ls leefile
leefile
清理未使用的 Docker 数据卷的命令
[root@docker ~]# docker volume prune
注意:
1、在执行 docker volume prune 命令之前,请确保你确实不再需要这些数据卷中的数据,因为该操作是不可逆的,一旦删除数据将无法恢复。
2、如果有重要的数据存储在数据卷中,建议先进行备份,或者确保数据已经被妥善保存到其他地方。
3.2 自行建立个使用数据卷示例
3.2.1 场景 1:需要 Docker 自动管理持久化数据(推荐生产环境使用)
# 1. 创建命名卷(Docker 自动在 /var/lib/docker/volumes/ 下创建规范目录)
docker volume create mydata
# 2. 容器挂载(无需指定宿主机路径!)
docker run -v mydata:/var/lib/mysql mysql
优势:Docker 确保路径结构合规,支持 docker volume inspect 查看真实路径,避免手动操作风险。
3.2.2 场景 2:需要自定义宿主机路径(仅限开发/测试)
# 1. 在 **非 Docker 管理目录** 创建路径(如 /mnt/app-data)
mkdir -p /mnt/app-data
# 2. 容器挂载(标准 Bind Mount)
docker run -v /mnt/app-data:/var/lib/mysql mysql
优势:路径完全由你控制,不干扰 Docker 内部状态。
3.2.3 查看卷
[root@docker ~]# docker volume ls
DRIVER VOLUME NAME
local leevol1
四、数据卷容器(Data Volume Container)
数据卷容器(Data Volume Container)是 Docker 中一种特殊的容器,主要用于方便地在多个容器之间共享数据卷。
可以让两个运行的容器的数据保持完全一致
4.1 建立数据卷容器
[root@docker ~]# docker run -d --name datavol \
-v /tmp/data1:/data1:rw \
-v /tmp/data2:/data2:ro \
-v /etc/resolv.conf:/etc/hosts busybox
4.2 使用数据卷容器
[root@docker ~]# docker run -it --name test --rm --volumes-from datavol busybox
/ # ls
bin data1 data2 dev etc home lib lib64 proc root sys tmp usr var
/ # cat /etc/resolv.conf
# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.
nameserver 114.114.114.114
search timinglee.org
# Based on host file: '/etc/resolv.conf' (legacy)
# Overrides: []
/ # touch data1/leefile1
/ # touch /data2/leefile1
touch: /data2/leefile1: Read-only file system
/ #
五、备份与迁移数据卷
5.1 备份数据卷示例
# 准备数据
# 运行容器
[root@docker-node1 ~]# docker run -d --name web -p 80:80 -v /data:/usr/share/nginx/html nginx:1.26
550aac17773f95e3180cf79cb23f483ebc5e7effa859cff6a47b3192a5c80784
# 创建文件
# 进入容器内部
[root@docker-node1 ~]# docker exec -it web bash
root@550aac17773f:/# cd /usr/share/nginx/html/
root@550aac17773f:/usr/share/nginx/html# touch file{1..10}
root@550aac17773f:/usr/share/nginx/html# ls
file1 file10 file2 file3 file4 file5 file6 file7 file8 file9
# 数据备份
# 创建一个新容器
[root@docker-node1 ~]# docker run -it --rm --volumes-from web -v `pwd`:/backup busybox:latest
# 备份
/ # tar zcf /backup/html.tar.gz /usr/share/nginx/html/
# 查看主机目录
[root@docker-node1 ~]# ls /root/html.tar.gz
/root/html.tar.gz
# 可见备份成功
5.2 数据恢复示例
# 先删除数据
[root@docker-node1 ~]# rm -rf /data/*
[root@docker-node1 ~]# docker exec -it web bash
root@550aac17773f:/# ls /usr/share/nginx/html/
# 直接删除容器
[root@docker-node1 ~]# docker rm -f web
web
# 重新运行一个容器
[root@docker-node1 ~]# docker run -d --name web -p 80:80 -v /data:/usr/share/nginx/html -v `pwd`:/backup nginx:1.26
1923f2ceb0b4f670168b01a6459a83aa1c98e7a79eaab56e8abd5a4c4294c309
# 数据恢复
[root@docker-node1 ~]# docker exec -it web bash
root@73002ccb070d:/# tar zxf /backup/html.tar.gz -C /
root@73002ccb070d:/# ls /usr/share/nginx/html/
file1 file10 file2 file3 file4 file5 file6 file7 file8 file9
六、bind mount 数据卷和docker managed 数据卷的对比
相同点:
-
两者都是 host 文件系统中的某个路径
不同点
| bind mount | docker managed volume | |
|---|---|---|
| volume 位置 | 可任意指定 | /var/lib/docker/volumes/... |
| 对已有mount point的影响 | 隐藏并替换为volume | 原有数据复制到volume |
| 是否支持单个文件 | 支持 | 不支持,只能是目录 |
| 权限控制 | 可设置为只读,默认为读写权限 | 无控制,均为读写权限 |
| 移植性 | 移植性弱,与host path绑定 | 移植性强,无需指定host目录 |
更多推荐

所有评论(0)