数据卷与持久化
🎯 引言
学完这篇文章,你能说清楚为什么容器删除后数据会消失,并掌握 Docker 保存数据的两种方式:目录挂载和数据卷。学完你就能放心地用 Docker 跑 MySQL 这类需要长期保存数据的软件,这正是后续数据库课程的必备知识。
🧱 为什么容器里的数据会丢
上一篇我们强调过:删除容器后,里面的数据会一起消失。这是因为容器里的文件存放在容器自己的文件系统里,容器就像一次性的盒子,盒子扔掉,里面的东西自然也没了。
学习阶段推倒重来无所谓,但真实场景不行:用 Docker 跑 MySQL,总不能接受删一次容器所有业务数据就清零。我们需要一种办法,让数据存放在容器之外,容器的生死不影响数据,这就是数据持久化。
🧱 什么是数据卷
Docker 提供的解决方案叫数据卷(Volume)。可以拿 U 盘类比:
- 容器像一台电脑,电脑(容器)坏了、换了都无所谓。
- 数据卷像 U 盘,数据存在 U 盘里,插到哪台电脑(容器)上都能用。
容器启动时把数据卷「挂载」到容器内的某个目录,容器读写这个目录时,实际上读写的是容器之外的数据卷。这样即使容器被删除,数据还好好地保存在数据卷里。
Docker 有两种常用的挂载方式:目录挂载和命名数据卷,下面分别来看。
🛠 方式一:目录挂载
目录挂载就是把本机的一个真实目录,映射到容器内的某个目录。用 -v 本机路径:容器内路径 指定。
举个例子,我们让 Nginx 展示自己写的页面。先在本机准备一个目录和页面:
mkdir ~/my-web
echo '<h1>Hello Docker</h1>' > ~/my-web/index.html
然后启动容器,把这个目录挂载到 Nginx 存放网页的目录:
docker run -d --name web -p 8080:80 -v ~/my-web:/usr/share/nginx/html nginx
打开浏览器访问 http://localhost:8080,看到的就是我们自己写的「Hello Docker」。更妙的是,你现在去修改 ~/my-web/index.html 的内容,刷新浏览器就能看到变化,容器不用重启。
🛠 方式二:命名数据卷
命名数据卷是由 Docker 统一管理的一块存储空间,你只需要给它起个名字,不用关心它具体存在磁盘的哪个位置。
以 MySQL 为例(后续 MySQL 课程会详细使用),MySQL 把数据存放在容器的 /var/lib/mysql 目录。我们创建一个名叫 mysql-data 的数据卷挂载上去:
docker run --name mysql8 -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -v mysql-data:/var/lib/mysql -d mysql:8
Docker 发现 mysql-data 这个卷不存在时会自动创建。现在即使你 docker rm mysql8 删掉容器,数据依然保存在 mysql-data 卷里。重新运行一条同样的命令,新容器挂载同一个卷,之前的数据原样找回。
查看和管理数据卷:
docker volume ls
docker volume rm mysql-data
docker volume rm 显式删除才会消失,删卷等于删数据,操作前请确认。另外 docker rm 删除容器时不会自动删除它的命名数据卷。⚡ 两种方式怎么选
- 目录挂载:你需要直接看到、修改这些文件时用。典型场景是挂载代码和配置文件,改完即生效。
- 命名数据卷:文件由软件自己管理、你不需要直接碰时用。典型场景是数据库的数据文件,交给 Docker 统一管理更省心。
一句话记忆:给人看的用目录挂载,给程序用的用数据卷。
🧾 小节总结
- 容器的文件存放在容器自己的文件系统里,删除容器数据即丢失,需要持久化的数据必须放到容器之外。
- 数据卷像 U 盘,数据存在容器之外,容器删除后数据仍在,新容器挂载同一卷即可找回数据。
- 目录挂载:
-v 本机路径:容器内路径,本机文件和容器实时同步,适合代码和配置。 - 命名数据卷:
-v 卷名:容器内路径,由 Docker 统一管理,适合数据库数据文件。 - 用
docker volume ls查看数据卷,docker volume rm删除数据卷,删卷即删数据。
❓ 知识问答
Q1:挂载之后,容器里原有的文件去哪了?
会被挂载的内容覆盖。比如把空的 ~/my-web 挂载到 Nginx 的网页目录,Nginx 自带的欢迎页就看不到了,看到的是挂载目录里的内容。
Q2:命名数据卷的文件实际存在哪里?
由 Docker 统一存放在它管理的目录下(Docker Desktop 内部)。平时不需要关心具体位置,用卷名操作即可。
Q3:多个容器可以共用一个数据卷吗?
可以。两个容器挂载同一个卷,就能共享里面的数据。但要注意多个程序同时写同一份数据可能互相干扰,数据库这类软件一般不要这么做。
Q4:学习阶段不挂载数据卷可以吗?
可以。学习时数据丢了重建就是,反而方便。但要清楚这个区别:不挂载,删容器数据就没;挂了卷,数据才安全。
Q5:目录挂载写相对路径可以吗?
建议写绝对路径(如 ~/my-web 或 /Users/你的用户名/my-web)。相对路径在不同执行位置含义不同,容易挂错目录还不报错,排查起来很费劲。
🧪 小练习
- 用目录挂载的方式运行一个 Nginx,让它展示你自己写的页面,然后修改页面内容并刷新浏览器,验证「改完即生效」:
# 提示:mkdir 建目录,echo 写 index.html,再 docker run 挂载
# 请在这里编写命令
- 用命名数据卷运行一个 MySQL 容器,进入客户端创建一个数据库,然后删除容器并重新运行,再次进入客户端查看数据库是否还在,验证数据卷的持久化效果:
# 提示:参考本文 MySQL 命令,用 docker exec -it mysql8 mysql -uroot -p 进入客户端
# 创建数据库的 SQL:CREATE DATABASE demo;
# 请在这里编写命令
🎉 恭喜你已经掌握了数据持久化的两种方式!下一篇我们更进一步,学习用 Dockerfile 把自己的 Node.js 应用打包成镜像。
