docker - 当我同时使用主机卷(绑定挂载)和命名卷(一种 docker 管理卷)时会发生什么?
问题描述
在问这个问题之前,我已经阅读了一些文件:
- https://docs.docker.com/glossary/?term=volume
- https://docs.docker.com/storage/
- https://docs.docker.com/storage/volumes/
- https://docs.docker.com/storage/bind-mounts/
我对以下两个部分感到困惑:
- 绑定挂载:挂载到容器上的非空目录
- 命名卷:使用容器填充卷
他们的行为完全相反:
对于绑定安装:
如果您绑定挂载到容器上的非空目录,则该目录的现有内容会被绑定挂载遮盖。
对于命名卷和匿名卷:
如果你启动一个容器来创建一个新的卷,如上,并且容器在要挂载的目录中有文件或目录(如上面的 /app/),则目录的内容将被复制到卷中。然后容器安装并使用该卷,并且使用该卷的其他容器也可以访问预填充的内容。
我的问题是,如果我VOLUME
在 dockerfile 中使用命令来创建一个命名卷匿名卷,同时使用绑定挂载将不存在的路径挂载到容器中,幕后发生了什么?
例如:
# in docker file
VOLUME /path/in/container
# when run container
docker run -v /not-exist-dir/in/host:/path/in/container ... /< image >
我做了一些测试,结果是:
- 没有创建匿名卷
/var/lib/docker/volumes/
- not-exist-dir 是在主机上创建的,现在它不是空的,我认为Populate a volume using a container已经生效。
所以,
- 为什么没有按预期创建匿名卷?
- 为什么目录的现有内容(在容器端)不会被绑定挂载遮盖?
这种情况背后发生了什么?
让我举一个更具体的例子:
这里是openfrontier/gerrit 镜像的 dockerfile,我们可以看到在 docker 文件的末尾,有一个 VOLUME 命令:
VOLUME $GERRIT_SITE
这实际上将在主机上创建一个匿名卷并将其挂载到/var/gerrit/review_site
容器中的(GERRIT_SITE 的值),当任何容器从这个图像创建时,如下所示:
docker run -dit --name gerrit openfrontier/gerrit:2.15.3
之后,我可以看到下面的匿名卷/var/lib/docker/volumes/
,我可以用docker volume ls
它来查看它的名称be4538dbf3a51da463391c6eca9714fb6dd0c11379f1e2918f74c33d56633f00
,也可以使用docker inspect gerrit
命令,我们可以看到:
"Mounts": [
{
"Type": "volume",
"Name": "be4538dbf3a51da463391c6eca9714fb6dd0c11379f1e2918f74c33d56633f00",
"Source": "/var/lib/docker/volumes/be4538dbf3a51da463391c6eca9714fb6dd0c11379f1e2918f74c33d56633f00/_data",
"Destination": "/var/gerrit/review_site",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
这两个文件夹下还有一些文件,是容器运行后创建的。
到目前为止,这是一个使用 VOLUME 命令创建匿名卷的正常示例。
但是,如果我使用以下命令运行此容器:
docker run -dit --name gerrit -v /home/test:/var/gerrit/review_site openfrontier/gerrit:2.15.3
where/home/test
主机上不存在,则不创建匿名卷,而是创建/home/test
文件夹且不为空!!!,挂载信息如下:
"Mounts": [
{
"Type": "bind",
"Source": "/home/test",
"Destination": "/var/gerrit/review_site",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
我认为绑定挂载在这里生效,但我只是不明白为什么主机上的路径不为空(因为绑定挂载到容器上的非空目录中,目录的现有内容被绑定挂载遮住了。)
在我使用启动容器之前,我还通过在“/home/test”下放置一些文件来测试将一个非空文件夹安装到docker run
容器,结果是保留了原始文件并添加了新文件。
我知道上面的例子不是使用 docker volume 的好习惯,但我只是想知道后面发生了什么。
解决方案
Dockerfile 中的卷声明在映像上设置了一些元数据,告诉docker run
在任何时候从该映像创建容器时在该位置定义一个匿名卷。这不是命名卷或主机挂载,但它与两者有很多共同点(默认情况下它们都是绑定挂载,并且匿名卷docker volume ls
与命名卷一起列出)。
但是,当您指定主机挂载到同一容器目录时,优先(不会发生两个卷挂载到容器内的同一目录)。容器内运行的命令对该目录的任何修改都将在主机上可见,但目录本身不会由图像内容初始化。
如果要使用映像内容初始化主机目录,可以使用执行绑定挂载的命名卷。与主机挂载的行为有一些不同。主要是目录必须预先存在,并且在撰写文件中您必须使用绝对路径而不是相对路径。我在这里的演示文稿中有语法:
https://sudo-bmitch.github.io/presentations/dc2018eu/tips-and-tricks-of-the-captains.html#48
推荐阅读
- c++ - 有什么方法可以设置用 g++ 构建的二进制文件的版本吗?
- java - 需要一种更有效的方法将 JDBC 结果集转换为 JSON 数组
- python - 有效地从多个列表中进行随机选择
- r - 将文本标签添加到 tmap 图中
- java - 从arrayList加载uri字符串时,格式错误的url异常没有协议
- python - 如何在openpyxl中将预先计算的误差线添加到条形图中
- c# - 将 Mosquitto 主题匹配功能从 C 翻译成 C#
- framebuffer - 如何保持粒子之间的协调以及哪个纹理像素包含每个人的信息?
- excel - Excel功能区在打开时未切换到选项卡
- jquery - 根据选择选项隐藏 div