首页  /  云原生  /  正文

Docker 数据卷与挂载

云原生 2026-10-02📖 13 分钟👁 —
🐳 云原生 · Docker第 4 / 9 页123456789📖 完整导航 →

一、为什么要有数据卷

容器里的数据是跟着容器走的,容器一删,写在里面的东西就一起没了。所以真正跑服务的时候,第一件事不是急着 docker run,而是先想清楚哪些目录得挂出去。

拿我搭 MySQL 主库那次来说,日志、数据、配置这三个目录我全都挂到了宿主机上,不挂的话容器一删库就没了:

docker pull mysql:5.7

# 1.创建主容器
docker run -p 3307:3306 --name mysql-master \
-v /mydata/mysql-master/log:/var/log/mysql \
-v /mydata/mysql-master/data:/var/lib/mysql \
-v /mydata/mysql-master/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
# 如果报错就去看日志
docker logs mysql-master
# 大部分情况都需要挂载mysql的三个目录
# 日志、数据、配置

也就是说:容器里的目录和宿主机上的目录,从此是同一份数据。日志能直接在宿主机上翻,配置能直接在宿主机上改,数据重启、升级容器都不会丢 —— 这就是数据卷存在的全部理由。

不过得提醒一句,挂载会同步后修改的数据,动重要文件之前想清楚。两边是双向同步的:宿主机上改完,容器里立刻就是新的;容器里写进去,宿主机上也马上出现。

早期还踩过一个坑,顺便记下来:宿主机上的目录如果是空的,挂上去会把容器里原来那个目录的内容整个盖住。挂配置文件的时候尤其要命,容器里原本的配置文件被空目录盖没了,服务直接起不来。所以挂载的目录层级、文件名要跟容器里对得上。


二、挂载的三种写法和卷的管理

-v 后面怎么写,决定了挂的是哪一种:

-v /宿主机路径:/容器内路径     # 绑定挂载,自己指定目录,最常用
-v 卷名:/容器内路径            # 具名卷,卷交给docker管,名字自己起
-v /容器内路径                 # 匿名卷,卷名是一串随机哈希

上面 MySQL 那三个目录就是绑定挂载,因为我想让数据固定落在 /mydata/mysql-master/ 下面,看得见、摸得着,备份的时候直接打包这个目录就行。

具名卷和匿名卷是把目录交给 docker 自己管,实际落在 /var/lib/docker/volumes/ 下面:

docker volume ls         # 列出所有卷,匿名卷就是一串哈希,看不出用途
docker volume inspect    # 看卷的详细信息,包括它到底落在宿主机哪个目录
docker volume rm         # 删卷
docker volume prune      # 清理没有被任何容器使用的卷

具名卷的好处是名字可控,docker volume ls 一眼能认出是哪个服务的;匿名卷只适合那种"数据丢了也无所谓"的临时目录,用 -v /容器内路径 一条就写完,不用自己先去建目录。

还有个读写的开关,写在最后面:

# 只读,容器里改不了,只能从宿主机改
-v 卷名:/容器内路径:ro
# 读写,默认就是这个
-v 卷名:/容器内路径:rw

镜像里其实也能声明卷,Dockerfile 里写一句 VOLUME /tmp,容器跑起来这个目录就自动是挂载状态 —— 这个在 Dockerfile 那两页里会碰到。等到写 compose 的时候,这里的挂载会在 yml 里统一写成 volumes: 那一段,放到后面 Compose 那一页说。


三、容器之间共享数据:--volumes-from

最土的办法是把同一个宿主机目录 -v 到多个容器上,更省事的是数据卷容器:专门起一个不干别的、只负责挂载的容器,其他容器用 --volumes-from 继承它的挂载。

# 数据卷容器,自己只管挂载
docker run -it --name centos01 -v /volume01 -v /volume02 centos

# 新容器直接继承它的挂载,两边看到的是同一份数据
docker run -it --name centos02 --volumes-from centos01 centos
centos02 用 --volumes-from centos01 继承挂载,两个容器之间就实现了数据同步
多个容器共用一个卷,箭头是双向的,改哪边另一边立刻同步

这么挂的好处是挂载点只写一次、跟着数据卷容器走(docker run 的时候不用每个容器都抄一遍)。生命周期也好理解:只要还有容器在用这个卷,数据就在;所有用了它的容器都删掉,这个卷才算真正结束使命。


四、挂载出来之后,怎么确认数据真的在

日志、配置挂出来之后可以直接在宿主机上 cat、tail;数据目录(比如 MySQL 的 /var/lib/mysql)里是二进制文件,看不了,得用客户端连上去验证:

在数据库管理工具里新建一个 MySQL 数据源,连到容器映射出来的端口,能看到库和表就说明挂载没问题

验证的套路是:先在容器里建库建表、写点数据,然后 docker rm -f 把容器删掉,再按同样的 -v 参数重新 docker run 一个 —— 数据还在,就说明这份数据确确实实落在宿主机上了。

还有一个细节:绑定挂载的目录最好提前建好。宿主机上没有这个目录时 docker 会自己建一个空目录,而空目录挂上去会把容器里原来那个目录整个盖住(就是前面踩的那个坑)。所以 -v 之前先 mkdir -p /mydata/xxx,挂完再确认一遍容器里原来的内容有没有被盖掉。

数据卷这块就这些。下一页拿两个 mysql 容器做一套主从,正好把挂载再用一遍。