在Docker中运行MySQL服务时,默认情况下MySQL的数据库文件、日志文件等都存储在容器内部的文件系统中,一旦容器被删除或者重建,这些内部数据就会全部丢失。要实现MySQL数据的持久化,核心思路就是将容器内MySQL的数据目录挂载到宿主机的持久化存储位置,通过数据卷的方式让数据脱离容器的生命周期独立存在。
MySQL数据持久化的核心原理
MySQL官方Docker镜像中,默认的数据存储目录是/var/lib/mysql,所有数据库表数据、事务日志、二进制日志等都存放在该目录下。我们只需要将这个目录通过Docker的卷挂载机制,映射到宿主机的指定目录或者Docker管理的卷中,就可以实现数据的持久化存储。
Docker提供了三种主要的卷挂载方式,其中适合MySQL数据持久化的主要有两种:Docker管理的命名卷、宿主机绑定挂载。匿名卷虽然也能实现持久化,但不便于用户直接管理,实际生产中使用较少。
方式一:使用Docker命名卷配置持久化
Docker命名卷是Docker引擎管理的持久化存储单元,用户不需要关心具体的宿主机存储路径,由Docker统一维护,适合对宿主机路径没有特殊要求的场景。
1. 创建命名卷
首先创建一个专门用于存储MySQL数据的命名卷,执行以下命令:
# 创建名为mysql_data的命名卷 docker volume create mysql_data
2. 启动MySQL容器并挂载命名卷
启动MySQL容器时,通过-v参数将命名卷挂载到容器内的/var/lib/mysql目录,同时需要设置MySQL的root密码,执行命令如下:
# 启动MySQL容器,挂载命名卷实现数据持久化 docker run -d --name mysql-test -p 3306:3306 -v mysql_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
上述命令中,-v mysql_data:/var/lib/mysql的作用就是将我们创建的mysql_data命名卷挂载到容器内的MySQL数据目录,容器写入/var/lib/mysql的所有数据都会实际存储到命名卷中。
3. 验证持久化效果
我们可以进入容器创建一个测试数据库,然后删除容器重新启动,验证数据是否保留:
# 进入运行中的MySQL容器 docker exec -it mysql-test mysql -uroot -p123456 # 在MySQL终端中创建测试数据库 CREATE DATABASE test_db; # 退出MySQL终端和容器 exit # 删除当前MySQL容器 docker rm -f mysql-test # 重新启动MySQL容器,使用同一个命名卷 docker run -d --name mysql-test -p 3306:3306 -v mysql_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0 # 再次进入容器查看数据库 docker exec -it mysql-test mysql -uroot -p123456 -e "SHOW DATABASES;"
执行后可以看到之前创建的test_db数据库仍然存在,说明数据已经通过命名卷实现了持久化。
方式二:使用宿主机绑定挂载配置持久化
宿主机绑定挂载是将宿主机的指定目录直接挂载到容器内,用户可以明确知道数据存储的宿主机路径,方便后续备份、迁移数据,适合需要自定义存储路径的场景。
1. 准备宿主机存储目录
首先在宿主机上创建一个用于存放MySQL数据的目录,并且需要修改目录权限,避免MySQL容器内用户没有写入权限:
# 创建宿主机目录 mkdir -p /data/mysql/data # 修改目录权限,确保容器内mysql用户(uid通常是999)可以读写 chmod 777 /data/mysql/data
2. 启动MySQL容器并挂载宿主机目录
启动容器时,将宿主机的/data/mysql/data目录挂载到容器的/var/lib/mysql目录,命令如下:
docker run -d --name mysql-test -p 3306:3306 -v /data/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0
3. 验证持久化效果
同样可以创建测试数据后删除容器重建,验证数据是否保留:
# 进入容器创建测试表 docker exec -it mysql-test mysql -uroot -p123456 -e "CREATE DATABASE test_db;USE test_db;CREATE TABLE user(id INT, name VARCHAR(20));INSERT INTO user VALUES(1, 'test');" # 删除容器 docker rm -f mysql-test # 重新启动容器,挂载同一个宿主机目录 docker run -d --name mysql-test -p 3306:3306 -v /data/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:8.0 # 查看数据是否保留 docker exec -it mysql-test mysql -uroot -p123456 -e "USE test_db;SELECT * FROM user;"
执行后可以查到之前插入的测试数据,说明绑定挂载方式也实现了数据持久化,此时我们也可以直接在宿主机的/data/mysql/data目录下看到MySQL的数据文件。
两种配置方式的对比
两种方式各有适用场景,以下是具体的对比:
| 对比项 | Docker命名卷 | 宿主机绑定挂载 |
|---|---|---|
| 存储路径管理 | 由Docker统一管理,用户无需关心具体路径 | 用户自定义宿主机路径,路径明确 |
| 权限配置 | Docker自动处理权限,无需手动调整 | 需要手动调整宿主机目录权限,避免权限问题 |
| 适用场景 | 无特殊路径要求,快速部署场景 | 需要明确数据位置,便于备份迁移场景 |
| 数据迁移 | 需要通过Docker命令导出卷数据 | 直接复制宿主机目录即可完成迁移 |
注意事项
- 挂载目录必须是MySQL容器内的
/var/lib/mysql,如果挂载其他目录无法实现数据持久化。 - 如果宿主机目录之前没有存放过MySQL数据,首次挂载启动容器时,MySQL会自动初始化数据目录,生成系统表等基础数据。
- 如果挂载的宿主机目录已经有数据,需要确保数据目录的权限和MySQL版本匹配,避免启动失败。
- 生产环境中建议同时挂载MySQL的日志目录,比如
/var/log/mysql,方便后续排查问题,挂载方式和数据目录一致。
总结
Docker环境下MySQL数据持久化的核心就是通过卷挂载将容器内的/var/lib/mysql目录映射到宿主机的持久化存储中,无论是使用Docker命名卷还是宿主机绑定挂载,都可以有效避免容器重启、删除导致的数据丢失问题。开发者可以根据实际的部署需求选择合适的挂载方式,在部署MySQL服务时优先配置数据卷,保障数据的安全性。