7

我是 Docker 世界的新手,我正在努力实现一些人们认为微不足道的事情。然而,似乎很多初学者在使用 Docker 时很难持久化他们的数据。

我使用Dockerfile构建了一个自定义图像。该容器运行MySQL 服务器,并且...是的,您猜对了:我想保留数据

这是我的 Dockerfile:

FROM debian:8.7

ENV MYSQL_ROOT_PASSWORD=test

RUN apt-get update -y && apt-get install -y apt-utils && \
    echo "mysql-server mysql-server/root_password password $MYSQL_ROOT_PASSWORD" | debconf-set-selections && \
    echo "mysql-server mysql-server/root_password_again password $MYSQL_ROOT_PASSWORD" | debconf-set-selections && \
    apt-get install -y mysql-server mysql-client && service mysql start

CMD service mysql start && /bin/bash

VOLUME /var/lib/mysql

EXPOSE 3306

我以这种方式构建和运行图像:

docker build -t mysql-persist-test:0.1 .
docker run -dt -v database_volume:/var/lib/mysql mysql-persist-test:0.1

到目前为止,一切都按预期工作,包括数据库。

但是,假设我想在我的主机上检索数据(Windows 10,我通过Docker Toolbox安装了 Docker )。

我使用Kitematic将本地文件夹“绑定”到命名卷(见下文),容器自动重新启动,然后……一切都坏了!目录中的所有文件都被删除有些是用所有者重新创建的,而不是./var/lib/mysql staffmysql

风筝

然后我有这些错误/var/log/mysql/error.log

...
/usr/sbin/mysqld: Table 'mysql.plugin' doesn't exist
170328 16:03:13 [ERROR] Can't open the mysql.plugin table. Please run mysql_upgrade to create it.
...
170328 16:03:13  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
...
170328 16:03:13  InnoDB: Starting an apply batch of log records to the database...
InnoDB: Progress in percents: 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
InnoDB: Apply batch completed
...
170328 16:03:14 [ERROR] Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist

我究竟做错了什么?

4

1 回答 1

11

卷层次结构

容器中的数据具有某种层次结构。它是这样的。

1.图像的一部分

这是最低级别,其中数据位于只读、不可变映像本身中。

2.在读写层

从图像启动容器后,会在现有图像层之上添加一个读写层。如果在容器中更改、添加或删除任何内容,默认情况下会写入此处。

此层中的更改会覆盖第 1 层中的数据。

3. Docker 卷

在您的示例中,您在 Docker 中创建了一个卷,其中

VOLUME /var/lib/mysql

这将在 Docker 中创建一个卷,可以在容器之间重用、持久化、共享等。如果/var/lib/mysql第 1 层有任何内容,则此卷的内容将覆盖。如果您在容器中进行更改,它们将在卷中进行(跳过第 2 层)。

4. 外卷

最后,我们有可以挂载在容器内的外部目录。这会覆盖所有其他。

由于它们基于外部目录,因此容器中所做的任何更改都可以从外部轻松访问。这大概就是您尝试这种方法的原因。

你怎么了

您从 Docker 卷(级别 3)开始,然后更改为外部卷(级别 4)。由于级别 4 覆盖了级别 3,因此会发生外部目录的内容(可能没有内容),覆盖 Docker 卷。因此容器只看到一个空目录。

你的文件还在。只需撤消外部挂载并返回到 Docker 卷;他们会在那里等着。

如何把你的文件拿出来

编辑:正如卡洛斯在评论中指出的那样,docker cp更简单,编辑使用这种方法。

docker cp <container-id>:/var/lib/mysql ./mydata

这会将 的内容复制/var/lib/mysql到文件夹mydata中。

于 2017-03-28T16:32:27.543 回答