首先,我想明确表示我在研究这个主题时已经做了尽职调查。密切相关的是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
命令之间共享持久状态,我为什么要指定 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
现在,确实,第二个容器会将数据挂载到上一个实例的 /foo
中。我可以在我的 Dockerfile 中不使用 VOLUME
来做到这一点。通过命令行,我可以将容器内的任何目录转换为挂载到主机上的绑定(bind)目录或 Docker 中的卷。
所以我的问题是:当您必须通过主机上的命令将命名卷显式映射到容器时,VOLUME
的意义何在?要么我遗漏了一些东西,要么这只是令人困惑和混淆。
请注意,我在这里的所有断言都是基于我对 docker 行为方式的观察,以及我从文档中收集到的内容。
最佳答案
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
指令确实是有代价的。
- 用户可能不知道正在创建未命名的卷,并且在删除容器后继续占用其 Docker 主机上的存储空间。
- 无法删除 Dockerfile 中声明的卷。下游镜像无法将数据添加到存在卷的路径。
后一个问题会导致类似的问题。
- How to “undeclare” volumes in docker image?
- GitLab on Docker: how to persist user data between deployments?
对于 GitLab 问题,有人想使用预配置的数据扩展 GitLab 镜像以进行测试,但由于 VOLUME at /var/opt/gitlab 的原因,不可能在下游镜像中提交该数据。在父图像中。
tl;dr:VOLUME
是为 Docker 1.9 之前的世界而设计的。最好别管它。
关于docker - Dockerfile 中 VOLUME 的实际用途是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52570093/