【问题标题】:How can I add a volume to an existing Docker container?如何将卷添加到现有 Docker 容器?
【发布时间】:2015-04-02 20:11:56
【问题描述】:

我有一个 Docker 容器,我只需在 Ubuntu 上安装 Docker 并执行以下操作即可:

sudo docker run -i -t ubuntu /bin/bash

我立即开始安装 Java 和其他一些工具,用了一段时间,然后停止了容器

exit

然后我想添加一个卷,并意识到这并不像我想象的那么简单。如果我使用sudo docker -v /somedir run ...,那么我最终会得到一个全新的容器,所以我必须安装 Java 并执行我之前已经完成的操作,才能到达一个已安装卷的容器。

所有关于从主机挂载文件夹的文档似乎都暗示挂载卷是在创建容器时可以完成的事情。因此,我必须避免从头开始重新配置新容器的唯一选择是将现有容器提交到存储库,并在安装卷时将其用作新容器的基础。

这确实是向现有容器添加卷的唯一方法吗?

【问题讨论】:

    标签: docker


    【解决方案1】:

    只需使用 Portainer。它重新创建容器并一键删除旧容器。

    【讨论】:

      【解决方案2】:

      您可以提交现有容器(即从容器的更改中创建新映像),然后使用新挂载运行它。

      例子:

      $ docker ps  -a
      CONTAINER ID        IMAGE                 COMMAND                  CREATED              STATUS                          PORTS               NAMES
          5a8f89adeead        ubuntu:14.04          "/bin/bash"              About a minute ago   Exited (0) About a minute ago                       agitated_newton
      
      $ docker commit 5a8f89adeead newimagename
      
      $ docker run -ti -v "$PWD/somedir":/somedir newimagename /bin/bash
      

      如果一切正常,请停止旧容器,并使用这个新容器。

      就是这样:)

      【讨论】:

      • 如果你因为某种原因需要新容器取旧名称,请在删除旧容器后使用docker rename
      • 只是想指出上面你提到newnameofcontainer 的地方可能应该命名为new_image_name——因为docker commit 在你的系统上创建了一个新的image .然后在下面当您执行docker run 时,您实际上使用了要从中运行新容器的 image 的名称。上述工作,但只是想向其他人澄清,上面的占位符 newnameofcontainer 实际上是新图像的名称。谢谢!很棒的答案。哦,您可以使用docker image ls 从第一个 docker commit 命令中看到新创建的图像
      • 其实,如果你想从一个镜像开始,你不需要提交一个新的容器。只要docker run -v /srv/a:/tmp ubuntu:14.04 就好了。
      • 这不会保留在原始容器中运行的进程。
      • 提交容器不会保留卷绑定,有什么解决方案吗?
      【解决方案3】:

      我们没有办法在运行的容器中添加音量,但是为了达到这个目的,你可以使用以下命令:

      在容器和本地文件系统之间复制文件/文件夹:

      docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
      
      docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH
      

      参考见:

      https://docs.docker.com/engine/reference/commandline/cp/

      【讨论】:

      • 挂载卷和将文件复制到容器和从容器复制文件之间存在巨大差异......
      • 无论如何它帮助了我。我不知道“docker cp”命令,并试图实现这一点 - 将文件从正在运行的容器复制到主机。
      • 它不是一个挂载,但它可以方便地在容器和本地主机之间来回传输文件。
      • 我不明白为什么有这么多赞成票,对于所提出的问题,这是一个非常错误的答案。
      • 这确实不完全是 OP 的情况,但我来这里是为了寻找一种将卷附加到 running 容器的方法。我的目标是在容器运行时动态地将一些内容输入/输出;假设我不控制容器创建并且没有停止它的选项。这个答案实际上指出了实现这一目标的唯一方法。所以,+1,谢谢!
      【解决方案4】:

      我已成功将主机的/home/<user-name> 文件夹挂载到现有(未运行)容器的/mnt 文件夹。您可以通过以下方式进行:

      1. 打开停止容器对应的配置文件,可以在/var/lib/docker/containers/99d...1fb/config.v2.json找到(对于旧版本的docker可能是config.json)。

      2. 查找MountPoints 部分,在我的情况下为空:"MountPoints":{}。接下来用类似这样的内容替换内容(您可以从另一个具有适当设置的容器中复制适当的内容):

      "MountPoints":{"/mnt":{"Source":"/home/<user-name>","Destination":"/mnt","RW":true,"Name":"","Driver":"","Type":"bind","Propagation":"rprivate","Spec":{"Type":"bind","Source":"/home/<user-name>","Target":"/mnt"},"SkipMountpointCreation":false}}
      

      或相同(格式化):

        "MountPoints": {
          "/mnt": {
            "Source": "/home/<user-name>",
            "Destination": "/mnt",
            "RW": true,
            "Name": "",
            "Driver": "",
            "Type": "bind",
            "Propagation": "rprivate",
            "Spec": {
              "Type": "bind",
              "Source": "/home/<user-name>",
              "Target": "/mnt"
            },
            "SkipMountpointCreation": false
          }
        }
      
      1. 重启docker服务:service docker restart

      这适用于 Ubuntu 18.04.1 和 Docker 18.09.0

      【讨论】:

      • 感谢您的回答。第 3 步至关重要。我还要补充一点,在写入之前最好先停止 docker 容器。
      • 这是最好的答案,因为它完全保留了现有的容器。这就是我所做的: 1. 停止 docker 引擎:systemctl stop docker.service 2. 编辑 config.v2.jsonvim &lt;(jq . /var/lib/docker/containers/&lt;container-ID&gt;/config.v2.json) 3. 将更新保存到文件::w config.v2.json 4. 退出 vim::q! 5. 更新现有文件:jq -c . config.v2.json &gt; /var/lib/docker/containers/&lt;container-ID&gt;/config.v2.json 6. 启动 docker 引擎:systemctl start docker.service 7. 必要时启动容器:docker start &lt;container-name/ID&gt; 8. 享受:-)
      • 关键步骤service docker restart。我尝试docker restart &lt;container&gt; 然后新配置没有被拾取,它被旧配置覆盖。
      • 另外jq 将有助于漂亮地打印 JSON,因此它是人类可编辑的:cat config.v2.json | jq . &gt; config.json
      • 在 Docker 版本 20.10.7 中,我似乎无法通过容器 id 找到 config.v2.json
      【解决方案5】:

      找了好久这个问题,使用Docker Windows容器的注意事项!

      条件:

      • Windows 10
      • Docker 桌面(最新版本)
      • 为映像 microsoft/mssql-server-windows-developer 使用 Docker Windows 容器

      问题:

      • 我想将主机字典挂载到我的 Windows 容器中。

      此处部分描述的解决方案:

      • 创建 docker 容器

      docker run -d -p 1433:1433 -e sa_password=&lt;STRONG_PASSWORD&gt; -e ACCEPT_EULA=Y microsoft/mssql-server-windows-developer

      • 转到容器中的命令外壳

      docker exec -it &lt;CONTAINERID&gt; cmd.exe

      • 创建目录

      mkdir DirForMount

      • 停止容器

      docker container stop &lt;CONTAINERID&gt;

      • 提交容器

      docker commit &lt;CONTAINERID&gt; &lt;NEWIMAGENAME&gt;

      • 删除旧容器

      docker container rm &lt;CONTAINERID&gt;

      • 使用新映像和卷安装创建新容器

      docker run -d -p 1433:1433 -e sa_password=&lt;STRONG_PASSWORD&gt; -e ACCEPT_EULA=Y -v C:\DirToMount:C:\DirForMount &lt;NEWIMAGENAME&gt;

      在此之后,我在 docker windows 容器上解决了这个问题。

      【讨论】:

        【解决方案6】:

        最好的方法是将所有文件和文件夹复制到本地文件系统上的目录中:docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

        SRC_PATH 在容器上 DEST_PATH 在本地主机上

        然后执行docker-compose down 将卷附加到相同的DEST_PATH 并使用docker-compose up -d 运行Docker 容器

        关注docker-compose.yml添加音量

        volumes:
         - DEST_PATH:SRC_PATH
        

        【讨论】:

        • 上面还有其他更好的选择。
        • 确实,上面有更好的选择,复制文件并没有挂载它们。此外,为 docker-compose 选项给出的“volumes”定义是相反的:volumes: - HOST_PATH:CONTAINER_PATH
        【解决方案7】:

        很遗憾,挂载卷的开关选项只能在run 命令中找到。

        docker run --help

        -v, --volume list Bind mount a volume (default [])

        有一种方法可以解决这个问题,这样您就不必重新安装已经在容器上设置的应用程序。

        1. 导出您的容器 docker container export -o ./myimage.docker mycontainer
        2. 作为图像导入 docker import ./myimage.docker myimage
        3. 然后docker run -i -t -v /somedir --name mycontainer myimage /bin/bash

        【讨论】:

        • 仅供参考 - docker container 不是 1.11.2 上的有效命令(这是撰写本文时 Synology 支持的最新版本)。不过,我找不到任何文档说明何时添加。在这种情况下,第一个命令是docker export -o ./myimage.docker mycontainer
        • 使用docker commit要容易得多,请参阅上面的答案stackoverflow.com/a/33956387/1260896
        • 这个虽然没有保留历史,但对于空间意识来说仍然是一个很好的解决方案。
        【解决方案8】:

        Jérôme Petazzoni 有一篇关于如何Attach a volume to a container while it is running 的非常有趣的博文。这不是 Docker 开箱即用的内置功能,但可以实现。

        正如他也指出的那样

        这不适用于不基于块设备的文件系统。

        只有在 /proc/mounts 正确列出了块设备节点时它才会起作用(正如我们在上面看到的,这不一定是真的)。​​

        另外,我只在本地环境中进行了测试;我什至没有尝试过云实例或类似的东西

        YMMV

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-09-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-26
          相关资源
          最近更新 更多