我有一个Dockerfile,在末尾声明了一个卷,如下所示:
VOLUME /data
现在,当我构建并运行此容器时,确实会创建一个新的卷,并挂载到/data
。
这很好,但我希望能够停止该容器,然后再次运行它,并确保相同的卷及其数据被重新挂载。
我如何做到这一点?
理想情况下,如果卷不存在,则相同的命令将创建该卷,并在卷已存在时重用它。
我有一个Dockerfile,在末尾声明了一个卷,如下所示:
VOLUME /data
现在,当我构建并运行此容器时,确实会创建一个新的卷,并挂载到/data
。
这很好,但我希望能够停止该容器,然后再次运行它,并确保相同的卷及其数据被重新挂载。
我如何做到这一点?
理想情况下,如果卷不存在,则相同的命令将创建该卷,并在卷已存在时重用它。
如果您希望将数据持久保存在容器的生命周期之外,则需要在容器之外创建卷。其中一种选项是创建“数据卷容器”,如文档中所述:
docker create -v /data --name my-data busybox /bin/true
这创建了一个名为my-data
的容器。它基于busybox
镜像,但因为我们使用的是create
而不是run
,所以实际上并没有启动任何东西。此容器仅存在以为其他容器提供卷。
然后,我们可以使用--volumes-from
选项访问该卷,当我们启动另一个容器时使用docker run
:
docker run --volumes-from my-data ...
现在你有一个在容器删除后仍然存在并且只要你的my-data
容器没有被删除就会持久化的卷。
或者,你可以在容器中挂载主机目录到/data
,例如:
docker run -v /path/on/host:/data ...
此选项在我上面链接的文档中同样有描述。
在使用命名卷出现之前,Larsks的回答是应该遵循的方式(或者至少是解决方法)。
现在只需使用命名卷,这更加简单和标准。
这很好,但我想能否停止此容器然后再次运行它,确保相同的卷及其数据被挂载回来。
如果您停止一个正在运行的容器(使用docker stop id
),然后再次启动它(使用docker start id
),与容器关联的卷仍将存在,无需使用命名卷或任何技巧,因为它仍然使用相同的容器。
卷不持久存在的问题发生在同一镜像的不同运行之间(docker run fooImageName
)。
匿名和命名卷
指定卷有两种形式:匿名和命名。
如果我们不指定名称,主机上的卷无法在下一次容器运行中重复使用,因为它是匿名的(但通过使用两个不同的容器:一个用于应用程序,另一个用于具有匿名卷的数据,可以解决这个问题,就像在Larsks的回答中一样)。
因此,由于卷是匿名的,Docker会为每个相同镜像的容器运行在主机上创建一个新的卷。
要使用命名卷,当我们运行容器时,只需在容器中挂载到文件/目录前缀名称(任何逻辑名称都可以)。
例如,在dockerfile中声明一个卷:
VOLUME /data
我们可以这样启动容器:
docker run -v my-volume:/data myImage
首次运行时创建卷。然后在任何下一次运行时,我们只需要指定已命名的卷 my-volume
以重用该卷。
这是文档中有趣的部分(重点是我的):
选择 -v 或 --mount 标记
...
-v
或--volume
:由三个字段组成,由冒号字符(:)分隔。字段必须按正确顺序,每个字段的含义不是立即明显的。
- 对于命名的卷,第一个字段是卷的名称,并且在给定主机上是唯一的。对于匿名卷,省略了第一个字段。
- 第二个字段是文件或目录在容器中挂载的路径。
- 第三个字段是可选的,并且是选项的逗号分隔列表,例如 ro。
作为替代方案,如果出于某些原因您需要在不启动容器的情况下创建卷,可以使用 docker volume
命令。
您可以在卷文档中阅读:
创建和管理卷
与绑定挂载不同,您可以在任何容器范围之外创建和管理卷。
创建一个卷:
$ docker volume create my-vol
我们将像以前一样使用它:
docker run -v my-volume:/data myImage
docker run -v
命令来定义。如果卷是在 Dockerfile 中指定的,则本地路径通常类似于/var/lib/docker/vfs/...
。您可以使用docker inspect -f {{.Volumes}} name
命令来查找。但是,Dockerfile 卷和run -v
卷之间存在差异。如果容器的基础镜像在指定的挂载点包含数据,则该现有数据将在卷初始化时复制到新卷中 - 但仅适用于 Dockerfile 卷。 - fnkr