如何在Docker容器中挂载主机目录

897

我正在尝试将主机目录挂载到Docker容器中,以便在主机上进行的任何更新都会反映在Docker容器中。

我在哪里做错了呢?以下是我的操作步骤:

kishore$ cat Dockerfile

FROM ubuntu:trusty
RUN apt-get update
RUN apt-get -y install git curl vim
CMD ["/bin/bash"]
WORKDIR /test_container
VOLUME ["/test_container"]

kishore$ tree
.
├── Dockerfile
└── main_folder
    ├── tfile1.txt
    ├── tfile2.txt
    ├── tfile3.txt
    └── tfile4.txt

1 directory, 5 files kishore$ pwd /Users/kishore/tdock

kishore$ docker build --tag=k3_s3:latest .

Uploading context 7.168 kB
Uploading context
Step 0 : FROM ubuntu:trusty
 ---> 99ec81b80c55
Step 1 : RUN apt-get update
 ---> Using cache
 ---> 1c7282005040
Step 2 : RUN apt-get -y install git curl vim
 ---> Using cache
 ---> aed48634e300
Step 3 : CMD ["/bin/bash"]
 ---> Running in d081b576878d
 ---> 65db8df48595
Step 4 : WORKDIR /test_container
 ---> Running in 5b8d2ccd719d
 ---> 250369b30e1f
Step 5 : VOLUME ["/test_container"]
 ---> Running in 72ca332d9809
 ---> 163deb2b1bc5
Successfully built 163deb2b1bc5
Removing intermediate container b8bfcb071441
Removing intermediate container d081b576878d
Removing intermediate container 5b8d2ccd719d
Removing intermediate container 72ca332d9809

kishore$ docker run -d -v /Users/kishore/main_folder:/test_container k3_s3:latest c9f9a7e09c54ee1c2cc966f15c963b4af320b5203b8c46689033c1ab8872a0ea

kishore$ docker run -i -t k3_s3:latest /bin/bash

root@0f17e2313a46:/test_container# ls -al
total 8
drwx------  2 root root 4096 Apr 29 05:15 .
drwxr-xr-x 66 root root 4096 Apr 29 05:15 ..

root@0f17e2313a46:/test_container# exit exit

kishore$ docker -v
Docker version 0.9.1, build 867b2a9

  • 我不知道如何检查boot2docker的版本

面临的问题和问题:

  1. 我需要将main_folder链接到docker容器内部存在的test_container文件夹中,应该怎样做?
  2. 我需要自动完成这个过程。不使用run -d -v命令,有什么方法可以实现?
  3. 如果boot2docker崩溃了会发生什么?除了Dockerfile之外,Docker文件存储在哪里?

2
FYI,根据此评论,这个问题在 Docker 中已经被解决了。我正在我的 Mac 上使用 Boot2Docker。我可以使用 -v 选项,将我的本地目录挂载到容器中。 - Marco
1
以下任何答案都不符合原帖中的第二个要求。他们想要从Dockerfile中实现,而不是使用docker run命令。我也在思考。 - Josh Albert
请不要给您的图像打上“latest”的标签!https://medium.com/@mccode/the-misunderstood-docker-tag-latest-af3babfd6375 - mteam88
27个回答

22

在Mac OS上,要将文件夹/Users/<name>/projects/挂载到您的容器根目录中:

docker run -it -v /Users/<name>/projects/:/projects <container_name> bash

ls /projects


17

如果主机是Windows 10,则请使用反斜杠而不是正斜杠 -

docker run -it -p 12001:80 -v c:\Users\C\Desktop\dockerStorage:/root/sketches

确保主机驱动器共享(在本例中为C)。在我的情况下,我运行上述命令后得到一个要求共享权限的提示。


15

对于Windows 10用户来说,将挂载点设置在C:/Users/目录内非常重要。我试了几个小时才使其正常工作。这篇文章有所帮助,但刚开始时并不明显,因为针对Windows 10的解决方案是对已接受答案的评论。以下是我的操作过程:

docker run -it -p 12001:80 -v //c/Users/C/Desktop/dockerStorage:/root/sketches \
<your-image-here> /bin/bash

接下来,您可以在图像内部执行echo TEST > hostTest.txt进行测试。您应该能够在本地主机文件夹中看到这个新文件,路径为C:/Users/C/Desktop/dockerStorage/


双斜杠路径是让它对我起作用的原因。这很令人困惑,因为我先使用了“-v $(pwd):/var/xx”,虽然它确实起作用,但结果是一个空目录。我正在通过Babun运行Cyg。 - kenchilada
在使用 /c/data/ 时,我在 Windows 7 上遇到了同样的问题,将主机目录移动到 /c/Users/<user>/ 下解决了我的问题。谢谢。 - user8675309
2
您可以提供解决问题的帖子链接吗? - PBo

13
自 Docker 18-CE 开始,您可以使用 docker run -v /src/path:/container/path 命令在主机文件夹和容器之间进行双向绑定。
但是,如果您正在 Windows 10/WSL 上工作,并且将 Docker-CE for Windows 作为主机,并在 WSL 中使用 docker-ce 客户端工具,则存在一个重大问题。WSL 知道整个 / 文件系统,而 Windows 主机仅了解驱动器。在 WSL 中,您可以使用 /mnt/c/projectpath,但是如果尝试 docker run -v ${PWD}:/projectpath,您会发现在主机上 /projectpath/ 是空的,因为在主机上 /mnt 没有意义。
但如果您从 /c/projectpath 开始工作,然后执行 docker run -v ${PWD}:/projectpath,则会发现在容器中,/projectpath 将实时反映 /c/projectpath。除了在客户机内看到空挂载点之外,没有错误或其他方式来检测此问题。
您还必须确保在 Docker for Windows 设置中“共享驱动器”。

我在Win10/WSL和Docker-CE/docker-ce上遇到了这个问题。/projectpath/为空。你说的“从/c/projectpath工作”是什么意思?我尝试将/c/链接到/mnt/c并从/c/projectpath运行,但是我得到了错误bind mount source path does not exist: /host_mnt/c/projectpath - Steven T. Snyder
这个链接解决了我的问题:http://support.divio.com/local-development/docker/how-to-use-a-directory-outside-cusers-with-docker-toolbox-on-windowsdocker-for-windows (在Windows上,Docker默认只允许从 /Users/ 挂载) - Steven T. Snyder

11

2015年7月的更新 - boot2docker现在支持直接挂载。您可以在Mac提示符中直接使用-v /var/logs/on/host:/var/logs/in/container,无需双重挂载。


11

我一直遇到同样的问题。 我的命令行看起来像这样:

docker run --rm -i --name $NAME -v `pwd`:/sources:z $NAME
问题出在 'pwd' 上,所以我把它改成了 $(pwd)。
docker run --rm -i --name $NAME -v $(pwd):/sources:z $NAME

1
z 是什么意思? - hhh
4
z选项表明绑定挂载内容在多个容器之间共享。 - Jason

8

如何将主文件夹链接到Docker容器内的test_container文件夹?

您下面的命令是正确的,除非您使用boot2docker的Mac系统(取决于未来的更新),否则您可能会发现该文件夹为空。有关纠正此问题的教程,请参见mattes的答案。

docker run -d -v /Users/kishore/main_folder:/test_container k3_s3:latest

我需要让它自动运行,如何做到不使用“run -d -v”命令。

你无法避免使用这些命令,因为它们是 Docker 工作的本质。你最好将它们放入 shell 脚本中,以节省重复编写的时间。

如果 boot2docker 崩溃会发生什么? Docker 文件存储在哪里?

如果你使用了 -v 参数并引用了你的主机,则文件将安全保存在主机上。

如果你使用了 "docker build -t myimage ." 命令,并使用 Dockerfile,则文件将被嵌入映像中。

您的 Docker 映像可能存储在 boot2docker-vm 中。当我从 VirtualBox 中删除 vm 时,我的映像就消失了。(注意,我不知道 Virtualbox 如何工作,因此映像可能仍然隐藏在其他地方,只是对 Docker 不可见。)


7

我发现像/var/usr/etc这样的系统目录下的任何文件夹都无法挂载到容器中。

用户空间应该放置指令,而-v开关指示docker守护进程将本地目录挂载到容器中,例如:

docker run -t -d -v /{local}/{path}:/{container}/{path} --name {container_name} {imagename}

7
我遇到了同样的问题。在docker文档中找到了解决方法:

注意:主机目录是与主机相关的。因此,您无法在Dockerfile中挂载主机目录,VOLUME指令不支持传递主机目录,因为构建的镜像应该是可移植的。主机目录在所有可能的主机上都不可用。

因此,在docker run命令中使用-v参数才能挂载读写主机目录,正如其他答案所指出的那样。

主机目录是什么? - Nicolas S.Xu
@NicolasS.Xu 任何实际的Docker主机机器上的路径。 - J. Scott Elblein
这个功能并不总是有用,所以让它永远没有用处,以保持一致性。 - Eric Duminil

7

以下是一个带有 Windows 路径的示例:

docker run -P -it --name organizr --mount src="/c/Users/MyUserName/AppData/Roaming/DockerConfigs/Organizr",dst=/config,type=bind organizrtools/organizr-v2:latest

作为一个附注,在所有这些令人抓狂的头发和反复解决和重新输入路径的过程中,我决定编写一个小的 AutoHotkey 脚本,将 Windows 路径转换为 "Docker Windows" 格式的路径。这样,我只需要将任何想要作为挂载点使用的 Windows 路径复制到剪贴板上,在键盘上按下 "Apps Key",它就会将其格式化为 Docker 所需的路径格式。
例如:
将此内容复制到剪贴板:
C:\Users\My PC\AppData\Roaming\DockerConfigs\Organizr 将光标放在命令行中想要的位置,按下 Apps Key,它就会将其粘贴到那里:
"/c/Users/My PC/AppData/Roaming/DockerConfigs/Organizr"
这为我节省了很多时间。这里提供给其他可能会发现它有用的人。
; --------------------------------------------------------------------------------------------------------------
;
; Docker Utility: Convert a Windows Formatted Path to a Docker Formatter Path
;                   Useful for (example) when mounting Windows volumes via the command-line.
;
; By:       J. Scott Elblein
; Version:  1.0
; Date:     2/5/2019
;
; Usage:    Cut or Copy the Windows formatted path to the clipboard, press the AppsKey on your keyboard
;           (usually right next to the Windows Key), it'll format it into a 'docker path' and enter it
;           into the active window. Easy example usage would be to copy your intended volume path via
;           Explorer, place the cursor after the "-v" in your Docker command, press the Apps Key and
;           then it'll place the formatted path onto the line for you.
;
; TODO::    I may or may not add anything to this depending on needs. Some ideas are:
;           
;           - Add a tray menu with the ability to do some things, like just replace the unformatted path
;               on the clipboard with the formatted one rather than enter it automatically.
;           - Add 'smarter' handling so the it first confirms that the clipboard text is even a path in
;               the first place. (would need to be able to handle Win + Mac + Linux)
;           - Add command-line handling so the script doesn't need to always be in the tray, you could
;               just pass the Windows path to the script, have it format it, then paste and close.
;               Also, could have it just check for a path on the clipboard upon script startup, if found
;               do it's job, then exit the script.
;           - Add an 'all-in-one' action, to copy the selected Windows path, and then output the result.
;           - Whatever else comes to mind.
;
; --------------------------------------------------------------------------------------------------------------

#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%

AppsKey::

    ; Create a new var, store the current clipboard contents (should be a Windows path)
    NewStr := Clipboard

    ; Rip out the first 2 chars (should be a drive letter and colon) & convert the letter to lowercase
    ; NOTE: I could probably replace the following 3 lines with a regexreplace, but atm I'm lazy and in a rush.
    tmpVar := SubStr(NewStr, 1, 2)
    StringLower, tmpVar, tmpVar

    ; Replace the uppercase drive letter and colon with the lowercase drive letter and colon
    NewStr := StrReplace(NewStr, SubStr(NewStr, 1, 2), tmpVar)

    ; Replace backslashes with forward slashes
    NewStr := StrReplace(NewStr,  "\", "/")

    ; Replace all colons with nothing
    NewStr := StrReplace(NewStr, ":", "")

    ; Remove the last char if it's a trailing forward slash
    NewStr :=  RegExReplace(NewStr, "/$")

    ; Append a leading forward slash if not already there
    if RegExMatch(NewStr, "^/") == 0
        NewStr :=  "/" . NewStr

    ; If there are any spaces in the path ... wrap in double quotes
    if RegExMatch(NewStr, " ") > 0
        NewStr :=  """" . NewStr . """"

    ; Send the result to the active window
    SendInput % NewStr 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接