简而言之:不,你的VOLUME指令不正确。
Dockerfile的VOLUME指定给定容器侧路径的一个或多个卷。但是它不允许映像作者指定主机路径。在主机端,卷是在Docker根目录中使用一个非常长的类似id的名称创建的。在我的机器上,这是/var/lib/docker/volumes
注意:由于自动生成的名称非常长,从人类的角度来看没有任何意义,因此这些卷通常被称为“未命名的”或“匿名的”。
你的例子中使用了a '。'字符甚至不会在我的机器上运行,无论我将圆点作为第一个参数还是第二个参数。我得到这个错误消息:
docker:来自daemon的错误响应:oci运行时错误:container_linux。Go:265:正在启动容器进程,导致“process_linux. exe”。Go:368: container init导致“open /dev/ptmx: no such file or directory”。
我知道在这一点上所说的对于试图理解VOLUME和-v的人来说可能不是很有价值,它当然不能为您试图实现的目标提供解决方案。所以,希望下面的例子能更清楚地说明这些问题。
Minitutorial:指定卷
给定这个Dockerfile:
FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2
(对于这个小教程的结果,如果我们指定vol1 vol2或/vol1 /vol2没有区别——这是因为Dockerfile中的默认工作目录是/)
构建:
docker build -t my-openjdk
Run:
docker run --rm -it my-openjdk
在容器内部,在命令行中运行ls,您将注意到存在两个目录;/vol1和/vol2。
运行容器还会在主机端创建两个目录或“卷”。
当容器运行时,在主机上执行docker volume ls,你会看到如下内容(为了简洁起见,我用三个点替换了名称的中间部分):
DRIVER VOLUME NAME
local c984...e4fc
local f670...49f0
回到容器中,执行touch /vol1/weird-ass-file(在指定位置创建一个空白文件)。
这个文件现在在主机上可用,在一个未命名的卷lol中。这花了我两次尝试,因为我第一次尝试了第一个列出的卷,但最终我在第二个列出的卷中找到了我的文件,在主机上使用以下命令:
sudo ls /var/lib/docker/volumes/f670...49f0/_data
类似地,您可以尝试在主机上删除该文件,它也会在容器中被删除。
注意:_data文件夹也被称为“挂载点”。
退出容器并列出主机上的卷。他们走了。我们在运行容器时使用了——rm标志,这个选项不仅在退出时有效地清除了容器,还清除了卷。
运行一个新的容器,但是使用-v指定一个卷:
docker run --rm -it -v /vol3 my-openjdk
这增加了第三个卷,整个系统最终有三个未命名的卷。如果我们只指定-v vol3,命令就会崩溃。参数必须是容器内的绝对路径。在主机端,新的第三个卷是匿名的,与其他两个卷一起驻留在/var/lib/docker/volumes/中。
前面说过,Dockerfile不能映射到主机路径,这给我们在运行时试图将文件从主机导入容器带来了问题。不同的-v语法可以解决这个问题。
假设我的项目目录./src中有一个子文件夹,我想把它同步到容器中的/src。这个命令很有用:
docker run -it -v $(pwd)/src:/src my-openjdk
字符的两边都需要一个绝对路径。左边是主机上的绝对路径,右边是容器内的绝对路径。PWD是“打印当前/工作目录”的命令。将命令放在$()中会得到圆括号内的命令,在子shell中运行它,并返回项目目录的绝对路径。
把所有这些放在一起,假设我们在主机上的项目文件夹中有。/src/Hello.java,内容如下:
public class Hello {
public static void main(String... ignored) {
System.out.println("Hello, World!");
}
}
我们构建这个Dockerfile:
FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello
我们运行这个命令:
docker run -v $(pwd)/src:/src my-openjdk
这上面印着“你好,世界!”
最好的部分是,我们完全可以在第二次运行时使用新消息修改.java文件,以获得另一个输出-而不必重新构建image =)
最后的评论
我对Docker很陌生,前面提到的“教程”反映了我从3天的命令行黑客马拉松中收集到的信息。我几乎感到羞愧,我不能提供清晰的英文文档链接来支持我的声明,但我真的认为这是由于缺乏文档,而不是个人努力。我确实知道这些例子是用我目前的设置“Windows 10 -> Vagrant 2.0.0 -> Docker 17.09.0-ce”来工作的。
本教程并没有解决“如何在Dockerfile中指定容器的路径,而让run命令只指定主机路径”的问题。也许有办法,只是我还没找到。
Finally, I have a gut feeling that specifying VOLUME in the Dockerfile is not just uncommon, but it's probably a best practice to never use VOLUME. For two reasons. The first reason we have already identified: We can not specify the host path - which is a good thing because Dockerfiles should be very agnostic to the specifics of a host machine. But the second reason is people might forget to use the --rm option when running the container. One might remember to remove the container but forget to remove the volume. Plus, even with the best of human memory, it might be a daunting task to figure out which of all anonymous volumes are safe to remove.