Dockerfile中VOLUME的实际用途是什么?

voi*_*ter 9 docker dockerfile

首先,我想明确表示我已经在研究这个主题方面做了尽职调查.非常密切相关的是这个问题,这并没有真正解决我的困惑.

我知道,当VOLUME在Dockerfile中指定时,这指示Docker在容器的持续时间内创建一个未命名的卷,该容器被映射到其内部的指定目录.例如:

# Dockerfile
VOLUME ["/foo"]
Run Code Online (Sandbox Code Playgroud)

这将创建一个卷来包含存储在/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
Run Code Online (Sandbox Code Playgroud)

我希望在两个run命令之间重用未命名的卷.然而,这种情况并非如此.因为我没有通过-v选项显式映射卷,所以为每个选项创建了一个新卷run.

这里有重要的第2部分:由于我需要明确指定-vrun命令之间共享持久状态,为什么我要VOLUME在Dockerfile中指定?没有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
Run Code Online (Sandbox Code Playgroud)

现在,真的,第二个容器将安装数据,/foo这是前一个实例的数据.我可以VOLUME在我的Dockerfile中执行此操作.从命令行,我可以将容器内的任何目录转换为主机上的绑定目录或Docker中的卷.

所以我的问题是:VOLUME当你必须通过主机上的命令显式地将命名卷映射到容器时,有什么意义呢?我要么缺少某些东西,要么就是混乱和混淆.

请注意,我在这里的所有断言都是基于我对docker行为的观察,以及我从文档中收集的内容.

Kin*_*ang 9

VOLUMEEXPOSE这样的指令有些不合时宜。我们今天所知道的命名卷是在大约三年前的Docker 1.9中引入的。

在Docker 1.9之前的版本中,运行一个其映像具有一个或多个VOLUME指令(或使用该--volume选项)的容器是创建用于数据共享或持久化的卷的唯一方法。实际上,过去的最佳实践是创建仅数据容器,其唯一目的是保存一个或多个卷,然后使用该--volumes-from选项与应用程序容器共享这些卷。这是一些描述这种过时模式的文章。

另外,请查看moby / moby#17798(docker 1.9.0上已淘汰的仅数据容器?),其中讨论了从仅数据容器到命名卷的更改。

今天,我认为该VOLUME说明是一种高级工具,仅在经过特殊考虑后,才应用于特殊情况。例如,官方的postgres图片声明VOLUME/var/lib/postgresql/data。通过将数据库数据保留在分层文件系统之外,这可以提高现成的postgres容器的性能。Docker不必遍历容器映像的所有层以查找文件请求/var/lib/postgresql/data

但是,该VOLUME指令确实要付出一定的代价。

  • 用户可能不知道正在创建的未命名卷,并在删除容器后继续占用其Docker主机上的存储空间。
  • 无法删除在Dockerfile中声明的卷。下游映像无法将数据添加到存在卷的路径。

后者会导致类似的问题。

对于GitLab问题,有人希望使用预先配置的数据来扩展GitLab映像以进行测试,但是由于父映像中/ var / opt / gitlabVOLUME,因此无法在下游映像中提交该数据。

tl; dr:VOLUME是为Docker 1.9之前的世界设计的。最好只是把它留在外面。

  • 这基本上就是答案,“历史”。命名卷过去并不存在,并且`--volumes-from` 很流行。另一个小补充是文档,比如 EXPOSE(技术上不需要,因为你可以用 `run` 做任何你想做的事情,它告诉消费者哪些位置 _should_ 是一个卷/保存持久数据)。 (2认同)
  • 我建议避免使用“ VOLUME”,但是“ EXPOSE”指令对于文档很有用。与“ VOLUME”不同,“ EXPOSE”指令没有任何有害的副作用。 (2认同)
  • 自从我发布这个问题以来,我意识到“VOLUME”仍然具有功能性目的:它允许您使用图像内部的数据初始化卷。如果我在“Dockerfile”中不使用“VOLUME”,但在执行“docker run”时仍然使用“-v”,如果映像将文件复制到,我的卷是否会使用容器中目录的当前内容进行初始化建造时的那个位置? (2认同)