Docker群是否会忽略Dockerfile中的VOLUME命令?

时间:2019-05-15 14:04:11

标签: docker docker-swarm docker-volume

我们正在部署一个堆栈,撰写文件列出了两项服务:

  • mediawiki
  • mySQL

我们看到mysql Dockerfile has a VOLUME directive将数据库持久存储到Docker卷

但是,如果我们docker stack rm然后docker stack deploy我们的撰写文件,我们将丢失所有数据库内容。

这是预期的行为吗?这样做的理由是什么?

3 个答案:

答案 0 :(得分:2)

Swarm模式不会生成Docker映像,因此可以肯定地说docker swarm忽略了Dockerfile的每一行。生成的图像将标识一个体积,该体积将在容器运行时创建,无论是在群集模式内部还是外部。如果您未在运行时指定卷装载,则docker将在该位置为您提供一个匿名卷,该卷稍后将难以识别,并且位于容器运行所在节点的本地。使用新堆栈时,将不使用以前的匿名卷,并且在各种情况下,可以自动删除匿名卷(例如,当容器配置为在退出时自动删除时,我不确定它是否适用于swarm模式)。

命名卷可以使数据更易于在单个节点群集中重用。进入多节点群集时,需要将此数据移出容器正在运行的节点。有关如何使用NFS之类的东西进行外部数据存储的详细信息,请参阅this answer到相关问题。

答案 1 :(得分:1)

Dockerfile有一个卷,但是您可能尚未在容器外部以可访问的方式挂载该卷,这意味着它可能没有被拉到持久性覆盖存储中以在容器/容器部署之间共享。

在docker-compose.yml文件的数据库服务中,您将需要一个volumes部分。我省略了您当前的设置,因为您没有提供它,而我将其替换为椭圆...

mySQL:
  ...
  volumes:
    - mySQL-data:/var/lib/mysql

这告诉系统您要将/var/lib/mysql目录保留在我随机命名为mySQL-data的共享叠加层中的容器之外。

答案 2 :(得分:1)

在这种情况下,处于群体模式并不重要。

如果仅依赖Dockerfile中定义的匿名卷,则运行新容器将创建并安装新的新卷。您需要在容器启动时专门挂载一个命名卷(在您的情况下,将其添加到撰写文件中)以在两次运行之间重新挂载相同的卷。

如果您需要重新挂载丢失的数据量,那么如果您不修剪服务器上的数据,仍然有可能。您只需要找到相关的卷(具有哈希名称),最终对其进行重命名并将其重新装入新容器中即可。

我玩了以下情况来说明我的观点:

首先获取图像,然后看看:

$ docker pull mysql:latest
$ docker image inspect mysql:latest

从这最后一条命令中,我们可以看到有一个为/var/lib/mysql声明的卷

我在我的开发机器上。清理所有内容,以便此时我没有卷

$ docker volume ls
DRIVER              VOLUME NAME
$

启动一个容器,然后再次查看卷

$ docker run -d --name test -e MYSQL_ALLOW_EMPTY_PASSWORD=1 mysql:latest 
37a92341f52b189d00636d1f03ecfbd4e3e7e5d55b685f5ec254971d7732566c
$ docker volume ls
DRIVER              VOLUME NAME
local               50f9810d13271c7c91b7e025e139db480f288a936f0a55f85d9580ef3aa83af7

现在将一些数据添加到容器中

$ docker exec -it test bash
root@37a92341f52b:/# mysql
Welcome to the MySQL monitor.  [... snip ...]
mysql> create database testso;
Query OK, 1 row affected (0.03 sec)
mysql> use testso;
Database changed
mysql> create table test (id int not null primary key);
Query OK, 0 rows affected (0.08 sec)
mysql> insert into test values (1);
Query OK, 1 row affected (0.05 sec)
mysql> select * from test;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

mysql> exit
Bye
root@37a92341f52b:/# exit
$ 

创建一个新容器

$ docker rm -f test
test
$ docker run -d --name test -e MYSQL_ALLOW_EMPTY_PASSWORD=1 mysql:latest
79148de09d7a3e13db338da133cfd7d44fe3590dc1c7ffe6129722c5c6baea21
$ docker volume ls
DRIVER              VOLUME NAME
local               50f9810d13271c7c91b7e025e139db480f288a936f0a55f85d9580ef3aa83af7
local               ef6fb2647c11c10ef98d25ca0dc2bd43231729ed18386c65768a0ad808fca93b

如您所见,我们还有新容器的第二卷。我不会在这里显示此信息,但是如果我连接,则数据将为空(与您的情况相同)。现在,让我们尝试恢复。

首先进行一些清理

$ docker rm -f test
test
$ docker volume rm ef6fb2647c11c10ef98d25ca0dc2bd43231729ed18386c65768a0ad808fca93b
ef6fb2647c11c10ef98d25ca0dc2bd43231729ed18386c65768a0ad808fca93b

我们想要一个易于理解的名称,但是我们不能重命名卷。我要做的是将旧的卷和新的命名卷挂载到busybox容器中,以传输数据。

$ docker run -it --rm -v 50f9810d13271c7c91b7e025e139db480f288a936f0a55f85d9580ef3aa83af7:/mysql/old -v mysql_data:/mysql/new busybox:latest 
/ # cd /mysql/
/mysql # mv old/* new/
/mysql # exit

我们现在有了这个新卷,我们可以摆脱匿名卷

$ docker volume ls
DRIVER              VOLUME NAME
local               50f9810d13271c7c91b7e025e139db480f288a936f0a55f85d9580ef3aa83af7
local               mysql_data
$ docker volume rm 50f9810d13271c7c91b7e025e139db480f288a936f0a55f85d9580ef3aa83af7
50f9810d13271c7c91b7e025e139db480f288a936f0a55f85d9580ef3aa83af7

最后,我们将命名卷重新装入一个新的mysql容器中,以取回数据

$ docker run -d --name test -e MYSQL_ALLOW_EMPTY_PASSWORD=1 -v mysql_data:/var/lib/mysql mysql:latest
3f6eff0b7660f3f8e9518564affc6555acb17184845156099d18300b3e76f4a2
$ docker exec -it test bash
root@3f6eff0b7660:/# mysql
Welcome to the MySQL monitor.  [... snip ...]

mysql> use testso
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from test;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.01 sec)