单个文件卷挂载为 Docker 中的目录
Posted
技术标签:
【中文标题】单个文件卷挂载为 Docker 中的目录【英文标题】:Single file volume mounted as directory in Docker 【发布时间】:2016-03-12 02:25:57 【问题描述】:Docker documentation 表示可以将单个文件挂载到 Docker 容器中:
-v 标志还可用于从主机挂载单个文件 - 而不仅仅是目录。
$ docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
这会将您放入新容器中的 bash shell,您将从主机获得 bash 历史记录,当您退出容器时,主机将获得在容器中键入的命令的历史记录。
当我尝试这样做时,文件会挂载为目录:
tom@u ~/project $ docker run --rm -it -v file.json:/file.json test
total 80K
drwxr-xr-x 9 root root 4.0K Dec 7 12:58 .
drwxr-xr-x 63 root root 4.0K Dec 7 12:58 ..
drwxr-xr-x 2 root root 4.0K Dec 4 16:10 file.json
我的 Dockerfile 看起来像这样:
FROM ubuntu:14.04
MAINTAINER Tom
CMD ["ls", "-lah", "/test"]
Docker 版本为 1.9.1,构建 a34a1d5。
这是一个文档问题,是我的误解,还是发生了其他事情?
【问题讨论】:
略有关联;如果您的 windows 密码更改并且您没有在 docker for windows 中更新它,您可能会看到所有挂载(文件或目录)显示为空目录 如果你使用--mount
而不是-v
,这个错误会很明显,因为mount
doesn't create directories automatically。
当您使用-v
并在左侧放置一个不带/
的字符串时,您实际上创建了一个命名卷。在这种情况下,file.json
将是您可以使用docker volume ls
查看的卷。
【参考方案1】:
也许上面的答案很清楚......但我花了一些时间才弄清楚我的情况。
导致与 -v 共享的文件显示为目录而不是文件的根本原因是 Docker 在主机上找不到该文件。因此 Docker 在容器中创建了一个新目录,名称为主机上不存在的文件的名称,因为 docker 认为用户只想共享将来创建的卷/目录。
所以在上面报告的问题中,如果你在 -v 命令中使用了相对目录并且 docker 不理解相对目录,这意味着在主机上没有找到该文件,因此 docker 创建了一个目录。当问题是由于相对目录引起时,上面建议使用 $(pwd) 的答案将是正确的解决方案。
但是对于那些没有使用相对目录并遇到相同问题的阅读此页面的人...然后尝试了解主机上缺少文件的原因。
这可能只是一个愚蠢的错字...
可能是您正在从客户端运行“docker run”命令,该命令在不同的主机上生成 docker 容器,并且正在共享的文件在该不同的主机上不存在。与 -v 共享的文件必须存在于 docker 代理将生成容器的主机上......不一定在执行“docker run -v ...”命令的客户端上(尽管它们在很多情况下)。
对于 Mac 和 Windows,上面还有其他可能的解释……也可能是这样。
所以问题是主机中缺少的文件...解决设置中的问题...使用 $(pwd) 可能是解决方案,但并非总是如此。
【讨论】:
很好的建议。 +1 是的,确实 +1。在某些用例中,如果您的容器应该创建此文件(并且它在主机上尚不存在),这确实不起作用(即“docker run ... -v $(pwd)/file.json:docker run
的观点非常有见地,帮助我解决了我的问题。谢谢!【参考方案2】:
test
是您使用“docker build -t test
”构建的映像的名称,而不是 /test
文件夹。
试试Dockerfile
:
CMD ["ls", "-lah", "/"]
or
CMD ["cat", "/file.json"]
还有:
docker run --rm -it -v $(pwd)/file.json:/file.json test
注意使用$(pwd)
以使用完整绝对路径挂载文件(不支持相对路径)
通过使用$(pwd)
,您将获得一个确实存在的绝对路径,并尊重大小写,而不是可能不存在的文件名或路径。
不存在的主机路径将作为文件夹挂载到容器中。
【讨论】:
谢谢,我按照你的建议试过了,但它显示一个空目录。 @TTT 然后尝试使用CMD ["ls", "-lah", "file.json"]
查看您的文件,或使用CMD ["cat", "/file.json"]
查看其内容
@TTT 你能试试用$(pwd)/
挂载它吗? docker run --rm -it -v $(pwd)/file.json:/file.json test
@TTT 太好了!为了提高可见性,我在答案中包含了绝对路径的使用。
请注意通过 Google 找到此内容的人,$(pwd)
是您来到这里的原因。 @Nikopol 在下面的回答非常详细地解释了这一点。 ***.com/a/44950494/117471【参考方案3】:
我花了一些时间来解决和诊断这个在 Windows 上运行 docker 的问题。这也可能会影响在 Mac OSX 上运行的人,因此我在此处为可能在这些环境中遇到问题的人添加了一个答案,因为我的搜索将我带到了这个地方,并添加了对 docker 中似乎正在发生的事情的解释。
在 Windows 或 Mac OSX 中,您的 docker 实际上在 boot2docker 虚拟机中运行,并且默认情况下实际上仅共享用户目录。在 Windows 上,这个用户目录被共享为 /c/Users/,但是在 Docker Machine 附带的 MinGW shell 中,驱动器可以作为 /C 或 /c 访问,所以如果你忘记了 docker 命令是实际针对 boot2docker 虚拟机运行,并且您的文件路径必须存在于 boot2docker 虚拟机上,并以它们存在的方式指定,因为在 docker 中似乎发生的是,而不是给出目录/文件的警告或错误不存在,docker 会在 boot2docker 虚拟机中默默地创建指定的源作为目录,因此没有准备好的输出表明您做错了什么。
因此,如上面的答案所示,如果您的文件作为目录挂载,请检查您是否提供了绝对路径。对于 Windows 和 Mac OSX,请检查您要挂载的绝对路径是否存在于您的 boot2docker 虚拟机中。
【讨论】:
Docker for Mac 似乎也是如此。 这对 docker 工具箱用户来说是一个非常有用的答案!如果您只想将文件添加到容器中,docker cp
命令可能很有用,如here 所述【参考方案4】:
在 docker 中运行 docker 时(例如通过挂载 /var/run/docker.sock
),您需要注意,如果您在 docker 中进行挂载,使用的文件路径始终是您主机上的文件路径。
因此,如果在您的主机上执行以下挂载:
-v /tmp/foobar.txt:/my/path/foobar.txt
您应该不在 docker 内执行以下挂载:
-v /my/path/foobar.txt:/my/other/path.txt
但是,请使用主机文件路径,例如:
-v /tmp/foobar.txt:/my/other/path.txt
【讨论】:
这正是我在使用 Gitlab CI 时所面临的。有没有办法从容器内部知道主机文件路径? 我不认为有,你最好的可能性是通过环境变量传递真实路径,例如【参考方案5】:Docker 可能找不到文件的情况,即使你确定它存在
正如 edi9999 指出的,如果你告诉 docker 守护进程挂载一个文件,它不会查看当前容器的文件系统,而是查看守护进程运行的文件系统。
如果您的 docker 守护程序由于某种原因在其他地方运行,您可能会遇到这个问题。
❯ docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock docker
/ # echo "bar" > /foo
/ # docker run --rm -v /foo:/foo ubuntu bash -c 'cat foo'
cat: foo: Is a directory
Docker 在它的主机上找不到 /foo 文件,所以它(有帮助吗?)在那里创建一个目录,所以至少你已经挂载了一些东西。
一种解决方法
您可以通过将主机目录挂载到外部容器中来解决此问题,然后将该目录用于您希望出现在内部容器中的卷:
❯ docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v /dev/shm:/dev/shm docker
/ # echo "bar" > /dev/shm/foo
/ # docker run --rm -v /dev/shm/foo:/dev/shm/foo ubuntu bash -c 'cat /dev/shm/foo'
bar
这使得路径/dev/shm/foo
在任一上下文中引用同一个文件,因此您可以从外部容器引用该文件,并且守护程序将在主机上找到它,这意味着它将在内部容器,而不是目录。
【讨论】:
【参考方案6】:对于“Docker for Mac/Windows”用户,请确保您尝试从主机挂载的卷是“文件共享”首选项的一部分:
【讨论】:
【参考方案7】:对于那些使用 VirtualBox 机器的人来说,有一个简单的解决方案。 默认情况下,添加 C:/User 文件夹。如果您的项目位于 C:/projects 中,请添加此文件夹以使其在 VB 中可用(使用自动挂载)。
【讨论】:
【参考方案8】:我遇到了与在我的 MacBook 上与 Docker 讨论的问题相同的问题,但没有任何建议对我有用。原来问题是我没有权限访问我试图挂载的文件(它由 root 拥有)。我将它复制到我的用户路径并将所有权更改为我自己,然后将文件安装为文件而不是目录。我认为,如果您没有权限,Docker 会将其解释为该文件根本不存在,然后继续将其挂载为新目录
【讨论】:
以上是关于单个文件卷挂载为 Docker 中的目录的主要内容,如果未能解决你的问题,请参考以下文章