【问题标题】:Does Docker swarm ignore VOLUME commands from Dockerfiles?Docker swarm 是否会忽略来自 Dockerfiles 的 VOLUME 命令?
【发布时间】:2019-10-02 17:04:04
【问题描述】:

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

  • 媒体维基
  • mySQL

我们看到mysql Dockerfile has a VOLUME directive,用于将数据库持久化到 Docker 卷

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

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

【问题讨论】:

    标签: docker docker-swarm docker-volume


    【解决方案1】:

    Swarm 模式不会构建 docker 镜像,因此可以肯定地说 docker swarm 会忽略 Dockerfile 的每一行。生成的图像将具有标识的卷,该卷将在容器运行时创建,无论是在集群模式内部还是外部。如果你没有在运行时指定一个卷挂载,docker 会在那个位置给你一个匿名卷,以后很难识别,并且是容器运行的节点的本地卷。使用新堆栈,不会使用之前的匿名卷,并且在各种情况下,可以自动删除匿名卷(例如,当容器配置为退出时自动删除时,我不确定它是否适用于 swarm模式)。

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

    【讨论】:

    • 我提供了 Dockerfile 作为 mysql 镜像创建方式的参考,当然本地 swarm 命令永远无法读取它。然而,你所描述的是我期望 Docker swarm 做的事情(给我一个匿名卷)。然而,似乎这个卷并没有在堆栈的不同部署中持续存在,这让我感到惊讶。 编辑:您的编辑清楚地表明我的期望是错误的,谢谢!
    • @AdN 匿名卷是...匿名的。它们没有详细说明它们的创建原因、关联的映像、挂载点的位置,因此 swarm 模式无法在堆栈的不同部署之间轻松重用它们。至少,您需要一个命名卷。
    【解决方案2】:

    Dockerfile 有一个卷,但您可能没有将该卷挂载为可在该容器外部访问,这意味着它可能没有被拉出到持久覆盖存储以在容器/容器部署之间共享。

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

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

    这告诉系统你想在我随机命名为mySQL-data的共享覆盖中的容器外部持久化/var/lib/mysql目录。

    【讨论】:

    • mySQL-data 是命名卷吗?如果是这样,它是否也应该在撰写文件的顶层声明?
    • 您不需要在独立部分中使用它,就像在网络中需要它一样。我相信这应该可以正常工作。
    【解决方案3】:

    在这种情况下,处于集群模式无关紧要。

    如果您仅依赖 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)
    

    【讨论】:

      猜你喜欢
      • 2012-03-29
      • 1970-01-01
      • 2016-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-12
      • 2020-12-16
      相关资源
      最近更新 更多