首先,我想澄清一下,我已经在研究此主题时进行了尽职调查。与this SO question密切相关,这并不能真正解决我的困惑。
我了解到,在Dockerfile中指定VOLUME
时,这会指示Docker在映射到容器内指定目录的容器期间创建未命名的卷。例如:
# Dockerfile
VOLUME ["/foo"]
这将创建一个卷以包含容器内/foo
中存储的所有数据。音量(当通过docker volume ls
查看时)将显示为随机的数字。
每次执行docker run
时,该卷均不会重复使用。这是造成混乱的关键。对我而言,卷的目标是包含在图像的所有实例(所有容器均从其启动)中持久存在的状态。所以基本上,如果我这样做,没有显式的卷映射:
#!/usr/bin/env bash
# Run container for the first time
docker run -t foo
# Kill the container and re-run it again. Note that the previous
# volume would now contain data because services running in `foo`
# would have written data to that volume.
docker container stop foo
docker container rm foo
# Run container a second time
docker run -t foo
我希望未命名的卷可以在2条run
命令之间重用。然而,这种情况并非如此。因为我没有通过-v
选项显式映射卷,所以将为每个run
创建一个新卷。
这是重要的部分2:由于需要显式指定-v
在run
命令之间共享持久状态,所以为什么我还要在Dockerfile中指定VOLUME
?没有VOLUME
,我可以做到这一点(使用前面的示例):
#!/usr/bin/env bash
# Create a volume for state persistence
docker volume create foo_data
# Run container for the first time
docker run -t -v foo_data:/foo foo
# Kill the container and re-run it again. Note that the previous
# volume would now contain data because services running in `foo`
# would have written data to that volume.
docker container stop foo
docker container rm foo
# Run container a second time
docker run -t -v foo_data:/foo foo
现在,确实,第二个容器将具有安装到先前实例中的/foo
的数据。我无需在Dockerfile中使用VOLUME
就可以做到这一点。从命令行,我可以将容器内的任何目录转换为主机上绑定目录或Docker中卷的装载。
因此,我的问题是:VOLUME
的意义是,无论如何必须通过主机上的命令将命名卷显式映射到容器?我丢失了某些东西,或者这只是令人困惑和混淆。
请注意,我在这里的所有断言都是基于我对docker的行为以及从文档中收集到的信息的观察。
答案 0 :(得分:5)
VOLUME
和EXPOSE
之类的指令有些不合时宜。我们今天所知的命名卷是在大约三年前的Docker 1.9中引入的。
在Docker 1.9之前,运行其映像具有一个或多个VOLUME
指令(或使用--volume
选项)的容器是创建用于数据共享或持久化的卷的唯一方法。实际上,过去的最佳实践是创建仅数据容器,其唯一目的是保存一个或多个卷,然后使用--volumes-from
选项与应用程序容器共享这些卷。这是一些描述这种过时模式的文章。
另外,请查看moby/moby#17798 (Data-only containers obsolete with docker 1.9.0?),其中讨论了从仅数据容器到命名卷的更改。
今天,我认为VOLUME
是一种高级工具,应经过仔细考虑,仅用于特殊情况。例如,官方的postgres图像声明了VOLUME
at /var/lib/postgresql/data
。通过将数据库数据保留在分层文件系统之外,这可以提高现成的postgres容器的性能。 Docker不必在容器映像的所有层中搜索/var/lib/postgresql/data
上的文件请求。
但是,VOLUME
指令确实要付出一定的代价。
后一个问题会导致类似的问题。
对于GitLab问题,有人想使用预先配置的数据来扩展GitLab映像以进行测试,但是由于父映像中的VOLUME at /var/opt/gitlab,因此无法在下游映像中提交该数据。
tl; dr:VOLUME
是为Docker 1.9之前的世界设计的。最好只保留它。