我们正在部署一个堆栈,撰写文件列出了两项服务:
我们看到mysql Dockerfile has a VOLUME
directive将数据库持久存储到Docker卷
但是,如果我们docker stack rm
然后docker stack deploy
我们的撰写文件,我们将丢失所有数据库内容。
这是预期的行为吗?这样做的理由是什么?
答案 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)