再也不用担心数据卷不翼而飞了
docker的本意就是只作为容器存在,任何配置或重要文件都应该以挂载的方式存在,像mysql
,redis
这种专门用来做数据库存储的容器,本身只提供了服务,真正的数据库数据并不在容器内,而是以docker的volume
数据卷的方式存在。
执行docker volume ls
看到我的电脑上当前存在的数据卷列表,目前我只运行了一个本地的redis
| |
此时我拉去一个mysql
镜像并运行,顺便创建了一个test
数据库,再次执行如下所示
| |
而docker inspect mysql
查看容器信息会发现这样的挂载形式,为了看清区别,我在启动mysql容器时额外挂在了一个普通文件
| |
看得出普通的挂载type类型是bind
,而数据卷的type类型是volume
,且它就存在于宿主机中,source
就是它的路径,可以cd进去看一下数据卷里都有什么
可以看到我之前创建的test
数据库在这里是以文件夹方式存在的,进入文件夹发现只有一个db.opt
配置文件,因为此时数据库是空的。为了看看数据是如何存放在数据卷中的,我随便建了个表并插入数据
create table a(a int); insert into a values(1);
此时再回到数据卷test
目录,多出两个以表名命名的文件,上网查了一下这两种后缀是InnoDB
引擎的存储方式
而以上都不是本文的重点。。只是顺便满足下好奇心,我想说的重点是在某种情况下,比如你发现当初运行mysql
容器时忘记把配置文件挂载出来,此时不论你用docker原始的方式还是修改docker-compose
之后up -d
,都会让容器内的数据丢失,因为最终都是要执行删除容器并重新启动一个新容器,所以会自动创建一个新的数据卷,所以我想知道如何在这种情况下把原来的数据卷挂载回去,这样不论如何删除,都使用同一个数据卷,就不会有数据丢失的问题了。
本以为很麻烦,其实答案就是上面那个docker inspect mysql
输出的容器信息里。里面明确地声明了把宿主机中的数据卷挂载到了容器中的/var/lib/mysql
位置
| |
所以我们面临两种情况:
- 当初不清楚也没考虑这么多,所以使用的是默认分类的数据卷,也就是上文遇到的问题,此时只需要再删除并重建容器时,把原来的数据卷位置以相同的方式挂载即可
docker run -it -v /var/lib/docker/volumes/20265b8be590fcef965a1fa8e544d3cd1c1424330abd86e81445839fb6516de0/_data:/var/lib/mysql mysql
唯一的不同就是现在的挂载类型type由volume
变成了bind
- 另一种情况就是知道这种默认行为,并在一开始就不使用默认数据卷,而是直接挂载在某处,比如
docker run -it -v /home/shingle/mysql/data/:/var/lib/mysql mysql
或者可以先创建一个带名字的数据卷,可以直接挂载使用
| |
| |
两种方式各有好处和弊端,使用默认的数据卷更方便docker进行管理,比如docker volume prune
会移除所有没被使用的数据卷,而自行挂载则需要先看到该镜像的文档,查找数据卷应该被挂载到哪里(比如mysql的/var/lib/mysql
),在以后不用的时候还需要手动删除。