3

docker挂载数据卷的行为和解决docker数据卷丢失的问题

 2 years ago
source link: https://shingle.me/post/docker%E6%8C%82%E8%BD%BD%E6%95%B0%E6%8D%AE%E5%8D%B7%E7%9A%84%E8%A1%8C%E4%B8%BA%E5%92%8C%E8%A7%A3%E5%86%B3docker%E6%95%B0%E6%8D%AE%E5%8D%B7%E4%B8%A2%E5%A4%B1%E7%9A%84%E9%97%AE%E9%A2%98/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

docker挂载数据卷的行为和解决docker数据卷丢失的问题

2017-11-09 15:55:14 约 1230 字 预计阅读 3 分钟 981 次阅读

再也不用担心数据卷不翼而飞了

docker的本意就是只作为容器存在,任何配置或重要文件都应该以挂载的方式存在,像mysql,redis这种专门用来做数据库存储的容器,本身只提供了服务,真正的数据库数据并不在容器内,而是以docker的volume数据卷的方式存在。

执行docker volume ls看到我的电脑上当前存在的数据卷列表,目前我只运行了一个本地的redis

DRIVER              VOLUME NAME
local               5c44cbef81c711c3b10ca64f79a7cb733655c05dc8949ab6005d44f103002a5f

此时我拉去一个mysql镜像并运行,顺便创建了一个test数据库,再次执行如下所示

DRIVER              VOLUME NAME
local               20265b8be590fcef965a1fa8e544d3cd1c1424330abd86e81445839fb6516de0
local               5c44cbef81c711c3b10ca64f79a7cb733655c05dc8949ab6005d44f103002a5f
local               f0042fac97c7c21710fd2a0e71306f7e34336fc30ac9b3f86e560edea32f0353

docker inspect mysql查看容器信息会发现这样的挂载形式,为了看清区别,我在启动mysql容器时额外挂在了一个普通文件

"Mounts": [
            {
                "Type": "bind",
                "Source": "/usr/share/zoneinfo/Asia/Shanghai",
                "Destination": "/etc/localtime",
                "Mode": "ro",
                "RW": false,
                "Propagation": "rprivate"
            },
            {
                "Type": "volume",
                "Name": "20265b8be590fcef965a1fa8e544d3cd1c1424330abd86e81445839fb6516de0",
                "Source": "/var/lib/docker/volumes/20265b8be590fcef965a1fa8e544d3cd1c1424330abd86e81445839fb6516de0/_data",
                "Destination": "/var/lib/mysql",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

看得出普通的挂载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位置

  "Source": "/var/lib/docker/volumes/20265b8be590fcef965a1fa8e544d3cd1c1424330abd86e81445839fb6516de0/_data",
                "Destination": "/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

    或者可以先创建一个带名字的数据卷,可以直接挂载使用

    volumes:
      mysql-data:
        driver: local
    
    volumes:
          - version-data:/var/lib/mysql
    

两种方式各有好处和弊端,使用默认的数据卷更方便docker进行管理,比如docker volume prune会移除所有没被使用的数据卷,而自行挂载则需要先看到该镜像的文档,查找数据卷应该被挂载到哪里(比如mysql的/var/lib/mysql),在以后不用的时候还需要手动删除。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK