Docker 简介

数据卷与持久化

理解容器数据丢失的原因,学会用目录挂载和数据卷把数据保存下来。

🎯 引言

学完这篇文章,你能说清楚为什么容器删除后数据会消失,并掌握 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)。相对路径在不同执行位置含义不同,容易挂错目录还不报错,排查起来很费劲。


🧪 小练习

  1. 用目录挂载的方式运行一个 Nginx,让它展示你自己写的页面,然后修改页面内容并刷新浏览器,验证「改完即生效」:
# 提示:mkdir 建目录,echo 写 index.html,再 docker run 挂载
# 请在这里编写命令
  1. 用命名数据卷运行一个 MySQL 容器,进入客户端创建一个数据库,然后删除容器并重新运行,再次进入客户端查看数据库是否还在,验证数据卷的持久化效果:
# 提示:参考本文 MySQL 命令,用 docker exec -it mysql8 mysql -uroot -p 进入客户端
# 创建数据库的 SQL:CREATE DATABASE demo;
# 请在这里编写命令

🎉 恭喜你已经掌握了数据持久化的两种方式!下一篇我们更进一步,学习用 Dockerfile 把自己的 Node.js 应用打包成镜像。