如何将卷添加到现有Docker容器中?


297

我有一个Docker容器,是通过在Ubuntu上安装Docker并执行以下操作而创建的:

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

我立即开始安装Java和其他一些工具,花了一些时间并通过以下方式停止了该容器

exit

然后我想添加一个卷,并意识到这并不像我想象的那么简单。如果使用的sudo docker -v /somedir run ...话,我将得到一个全新的容器,因此我将安装Java并做我已经做的事,然后再到达一个具有已安装卷的容器。

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

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


1
在容器之后,这些已成为程序员不可或缺的一部分,因此,此类问题在这里的发布频率更高。使用docker标签在此处发布的问题为34k +,远远超过这两个站点stackoverflow.com/questions/tagged/docker
MA Hossain Tonu,

Answers:


394

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

例:

$ 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/dir1":/dir1 -v "$PWD/dir2":/dir2 newimagename /bin/bash

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

而已 :)


22
并且如果出于某种原因需要新容器采用旧名称,请在删除旧容器后使用docker重命名
德克

10
只是想指出您在上面提到的newnameofcontainer这个名称new_image_name,因为它docker commit会在系统上创建一个新映像。然后,当您执行以下操作时,docker run您实际上会使用要从中运行新容器的映像的名称。上面的方法有效,但只是想向其他人澄清,上面的占位符newcontainer实际上是新图像的名称。谢谢!很棒的答案。哦,您可以使用docker image ls
FireDragon's

3
实际上,如果要从映像开始,则不需要提交新的容器。只要docker run -v /srv/a:/tmp ubuntu:14.04是好的。
YongHaoHu

我已经有一个运行着所有文件的容器。如果以上方法创建了新容器,我将无法再次构建所有内容。有没有一种方法可以避免这种情况并且无需创建新的容器或映像就可以挂载?
迪纳尔

这将保留旧容器中的旧卷映射,还是我也应使用新容器重新声明它们?
thebeancounter

79

我们没有任何方法可以在正在运行的容器中添加卷,但是要实现此目标,您可以使用以下命令:

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

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

供参考,请参阅:

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


47
在装入卷和在容器之间复制文件之间存在巨大的区别……
Jules,

31
无论如何它帮助了我。我不知道'docker cp'命令,并且正试图实现这一目标-将文件从正在运行的容器复制到主机。
伊万

3
它不是坐骑,但在容器和本地主机之间方便地带回文件很方便。
linehrr

尽管这确实解决了在本地复制容器内容的问题,但这并不等同于安装卷,因此不应将其视为替代方法。即,复制必须由用户管理,并且数据现在存在于两个位置。
塞巴斯蒂安·加威达'19

1
我不明白为什么要进行如此多的投票,这对于提出的问题来说是一个非常错误的答案。
若昂·马托斯

33

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

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

  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容器。
buzypi

7
这是最好的答案,因为它可以完全保留现有容器。这就是我所做的:1.停止docker引擎:systemctl stop docker.service2.编辑config.v2.jsonvim <(jq . /var/lib/docker/containers/<container-ID>/config.v2.json)3.将更新保存到文件中::w config.v2.json4.退出vim::q!5.更新现有文件:jq -c . config.v2.json > /var/lib/docker/containers/<container-ID>/config.v2.json6.启动docker引擎:systemctl start docker.service7.必要时启动容器:docker start <container-name/ID>8. Enjoy :-)
Android Control

2
一个关键步骤service docker restart。我试图docker restart <container>然后不提取新的配置,并且它被旧的配置覆盖。
KFL

1
这也jq将有助于漂亮地打印JSON,因此它可以手动编辑:cat config.v2.json | jq . > config.json
KFL

14

JérômePetazzoni撰写了一篇非常有趣的博客文章,内容涉及如何在运行时将卷附加到容器。这不是Docker内置的内置功能,但是可以实现。

正如他还指出的那样

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

仅当/ proc / mounts正确列出了块设备节点(如上所示,它不一定为true)时,它才起作用。

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

青年汽车


8

不幸的是,只能在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

1
FYI- docker container在1.11.2(这是Synology撰写本文时所支持的最新版本)上不是有效命令。不过,我找不到任何说何时添加的文档。在这种情况下,第一个命令是docker export -o ./myimage.docker mycontainer
克里斯·唐纳利

2

在长时间寻找这个问题之后,有关使用Docker Windows容器的说明!

条件:

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

问题:

  • 我想将主机字典安装到Windows容器中。

解决方案部分描述如下:

  • 创建Docker容器

docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y microsoft/mssql-server-windows-developer

  • 转到容器中的命令外壳

docker exec -it <CONTAINERID> cmd.exe

  • 创建目录

mkdir DirForMount

  • 停止容器

docker container stop <CONTAINERID>

  • 提交容器

docker commit <CONTAINERID> <NEWIMAGENAME>

  • 删除旧容器

docker container rm <CONTAINERID>

  • 创建具有新映像和卷安装的新容器

docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y -v C:\DirToMount:C:\DirForMount <NEWIMAGENAME>

之后,我在Docker Windows容器上解决了这个问题。


-3

最好的方法是通过以下方式复制本地文件系统中目录内的所有文件和文件夹: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

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

然后docker-compose down将卷附加到该卷DEST_PATH并通过使用来运行Docker容器docker-compose up -d

按照以下步骤添加音量 docker-compose.yml

volumes:
 - DEST_PATH:SRC_PATH

上面还有其他更好的选择。
MrR

确实,上面有更好的选择,并且复制文件不会挂载它们。另外,为docker-compose选项提供的“ volumes”定义是相反的:volumes:-HOST_PATH:CONTAINER_PATH
Guillaume S.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.