Dockerfile中的VOLUME有什么作用

时间:2018-10-17 19:57:52

标签: docker dockerfile

我正在尝试了解以下DockerFile:

https://github.com/nfnty/dockerfiles/blob/master/images/arch-bootstrap/latest/Dockerfile

FROM nfnty/arch-mini:latest
.....
RUN     install --directory --owner=root --group=root --mode=700 /var/lib/bootstrap/{,archive}

USER root
VOLUME ["/var/lib/bootstrap"]
ENTRYPOINT ["/opt/bootstrap/build.sh"]

RUN正在创建目录/ var / lib / bootstrap / archive,并且在构建后,映像将永久具有此文件夹

从中创建容器时,由于其存在于映像中,因此它将具有文件夹“ / var / lib / bootstrap / archive”。

声明VOLUME / var / lib / bootstrap /

有什么意义?

我可以在命令行中理解-v [主机路径]:[container:path]会将主机文件夹安装在容器文件夹上。

但是dockerfile中的Volumne是什么,尤其是在上述情况下。

好的,我正在显示一些我已经完成的测试:

-- trying to create a container with dockerfile above
i.e VOLUME ["/var/lib/bootstrap"]

hostsystem#  docker run -it --entrypoint=/bin/bash nfnty/arch-bootstrap
[root@684120b46cfb /]# ls -al /var/lib/bootstrap/
total 12
drwx------ 3 root root 4096 Oct 18 05:53 .
drwxr-xr-x 1 root root 4096 Aug 23 12:48 ..
drwx------ 2 root root 4096 Aug 23 12:48 archive

-- I have created a sample001.txt file inside it.
[root@684120b46cfb /]# touch /var/lib/bootstrap/sample001.txt
[root@684120b46cfb /]# ls -al /var/lib/bootstrap/
total 12
drwx------ 3 root root 4096 Oct 18 05:54 .
drwxr-xr-x 1 root root 4096 Aug 23 12:48 ..
drwx------ 2 root root 4096 Aug 23 12:48 archive
-rw-r--r-- 1 root root    0 Oct 18 05:54 sample001.txt
[root@684120b46cfb /]# 

[root@684120b46cfb /]# exit

-- As per [@izazkhan answer][1] the VOLUME ["/var/lib/bootstrap"]
instruction is persisting the data by creating a volume in 
/var/lib/docker on the host and mount it on /var/lib/bootstrap 
in the container. So expect the sample001.txt lies there at 
/var/lib/docker/(var/lib/bootstrap)

-- Now again trying to create a container
hostsystem#  docker run -it --entrypoint=/bin/bash nfnty/arch-bootstrap
[root@5fa7c4fc72e2 /]# ls -al /var/lib/bootstrap/
total 12
drwx------ 3 root root 4096 Oct 18 06:00 .
drwxr-xr-x 1 root root 4096 Aug 23 12:48 ..
drwx------ 2 root root 4096 Aug 23 12:48 archive
[root@5fa7c4fc72e2 /]# 

-- i dont see my sample001.txt file here.

And i check the dockers:

#  docker container ls -a
CONTAINER ID        IMAGE                  COMMAND             CREATED             STATUS                      PORTS               NAMES
ff2d37e5399a        nfnty/arch-bootstrap   "/bin/bash"         16 seconds ago      Exited (0) 3 seconds ago                        stupefied_sinoussi
bfbff0778fe9        nfnty/arch-bootstrap   "/bin/bash"         7 minutes ago       Exited (0) 30 seconds ago                       objective_noether


And i check the volumes:

#  docker volume ls
DRIVER              VOLUME NAME
local               47ae26f1b4b17cd2792972b50dcae9da9af1d3f06ccd984cfbf5a75be7365bbd
local               fd5a1caf07024f7103a3a225f4de00a2c1efb79a74fa939737f11c939837b32a

What i found is there are two volumes since i have created two containers.

-- Also checking the volume folders:

# cd /var/lib/docker/volumes

#  find . -exec ls -dl \{\} \; | awk '{print $3, $4, $9}'
root root .
root root ./47ae26f1b4b17cd2792972b50dcae9da9af1d3f06ccd984cfbf5a75be7365bbd
root root ./47ae26f1b4b17cd2792972b50dcae9da9af1d3f06ccd984cfbf5a75be7365bbd/_data
root root ./47ae26f1b4b17cd2792972b50dcae9da9af1d3f06ccd984cfbf5a75be7365bbd/_data/archive
root root ./fd5a1caf07024f7103a3a225f4de00a2c1efb79a74fa939737f11c939837b32a
root root ./fd5a1caf07024f7103a3a225f4de00a2c1efb79a74fa939737f11c939837b32a/_data
root root ./fd5a1caf07024f7103a3a225f4de00a2c1efb79a74fa939737f11c939837b32a/_data/archive
root root ./fd5a1caf07024f7103a3a225f4de00a2c1efb79a74fa939737f11c939837b32a/_data/sample001.txt
root root ./metadata.db

我希望在任何容器中都可以看到sample001.txt。即所有容器都使用相同的卷文件夹。但是看起来它们在/ var / lib / docker / volumes中创建了不同的文件夹,即使挂载点是由dockerfile中的VOLUME定义的。

我很困惑,dockerfile中的VOLUME是指主机上位于/ var / lib / docker / volumes的单个文件夹,而不管我们创建了多少个容器。但这不是事实,因为它们在每个容器的/ var / lib / docker / volumes中具有不同的主机文件夹。

那么VOLUMES的目的是什么。我感觉到的一种帮助是,如果我在容器中创建一些文件并将其存储在VOLUME位置,并且我想从主机访问它们,那么我可以去检查卷文件夹。

但是,卷文件夹的名称很难确定它们属于哪个容器。

对不起,我对docker中的卷是完全陌生的,我是-v [host]:[container],但第一次遇到dockerfile中的VOLUME。所以我完全感到困惑,无法弄清楚发生了什么。

在阅读https://docs.docker.com/storage/volumes/之后,我找到了为什么音量大的答案

  

此外,与将数据持久存储在其中相比,卷通常是更好的选择   容器的可写层,因为体积不会增加   使用它的容器的大小以及该卷的内容是否存在   在给定容器的生命周期之外。

下面的链接也有助于了解如何拥有一个共同的体积并在不同的容器中使用它(与我的问题不同)

https://linuxhint.com/storing-sharing-docker-volumes/

3 个答案:

答案 0 :(得分:3)

Docker卷:

卷使存储在其中的数据的寿命与创建它们的容器的寿命脱钩。这样一来,您就可以docker rm my_container并且不会删除您的数据。

可以通过两种方式创建卷:

在Dockerfile中指定VOLUME /some/dir

将其作为运行命令的一部分指定为docker run -v /some/dir

无论哪种方式,这两件事都是完全一样的。它告诉Docker在主机上的Docker根路径(默认为/var/lib/docker)内创建目录,并将其安装到您指定的路径(上面的/some/dir)中。当您使用该卷删除容器时,该卷本身将继续存在。

如果指定的路径在容器内不存在,则会自动创建目录。

您可以告诉docker连同容器一起删除卷:

docker rm -v my_container

有时候您的主机上已经有一个要在容器中使用的目录,因此CLI拥有一个用于指定此内容的额外选项:

docker run -v /host/path:/some/path ...

这告诉docker具体使用指定的主机路径,而不是在docker根目录中创建自身,然后将其安装到容器内的指定路径(上述/some/path)。

请注意,这也可以是文件而不是目录。在Docker术语中,这通常称为绑定安装(尽管从技术上讲,从实际发生的意义上讲,所有卷都是绑定安装)。如果主机上的路径不存在,则会在给定路径上自动创建目录。

来自docker文档:

VOLUME ["/data"]

VOLUME指令创建具有指定名称的安装点,并将其标记为保存来自本机主机或其他容器的外部安装的卷。该值可以是JSON数组VOLUME ["/var/log/"],也可以是带有多个参数的纯字符串,例如VOLUME /var/logVOLUME /var/log /var/db。有关通过Docker客户端的更多信息/示例和安装说明,请参阅“通过卷共享目录”文档。

docker run命令使用基本映像内指定位置上存在的任何数据初始化新创建的卷。例如,考虑以下Dockerfile片段:

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

此Dockerfile生成一个映像,该映像使docker run在/myvol处创建一个新的挂载点,并将问候文件复制到新创建的卷中。

答案:

因此,在上述情况下,VOLUME ["/var/lib/bootstrap"]指令通过在主机上的/var/lib/docker中创建一个卷并将其装入容器中的/var/lib/bootstrap上来保留数据。

有关指定卷的说明

请记住有关Dockerfile中的卷的以下事项。

基于Windows的容器上的卷:使用基于Windows的容器时,该容器内的卷的目标必须是以下其中之一:

  • 不存在或空目录
  • 除C以外的驱动器:

从Dockerfile内更改卷::如果在声明了卷后有任何构建步骤更改了卷中的数据,则这些更改将被丢弃。

JSON格式:该列表被解析为JSON数组。您必须用双引号(“)而不是单引号(')括住单词。

主机目录在容器运行时声明:从本质上来说,主机目录(挂载点)取决于主机。这是为了保留图像的可移植性,因为不能保证给定的主机目录在所有主机上都可用。因此,您无法从Dockerfile中挂载主机目录。 VOLUME指令不支持指定host-dir参数。创建或运行容器时,必须指定安装点。

答案 1 :(得分:0)

Dockerfile中的VOLUME指令的意思是:

  

从该映像创建的每个容器都会有其自己的专有   目录以保留其数据。如果您不使用自己的目录或远程挂载覆盖它,则dockerd将在主机中的/var/lib/docker/volumes下分配一个随机目录。

尽管可以,但Docker并未假设卷数据将在容器之间共享。相反,它假定卷内的数据仅应由运行在一个特定容器中的应用程序实例使用。

大多数保留任何内容的应用程序通常都是这种情况。例如,您不能有两个MySQL实例竞争将数据存储到同一/var/lib/mysql目录中。分布式键值存储,例如etcd,不需要共享持久数据。每个实例加入群集后都会同步/克隆。

由于这些假设,我本人发现VOLUME指令有点令人讨厌。它假设每次运行容器时都希望数据持久化。出于开发/测试目的,几乎从来没有这样。作为开发人员,我需要经常清理那些坚持让卷悬而未决的容器。

尽管在生产环境中情况恰好相反,但是这种默认的“ /var/lib/docker/volumes内部的随机目录”几乎从来都不是一个好主意。自动配置卷的云解决方案肯定会在其他位置进行配置。对于其他所有内容,您都希望控制在何处以及如何创建卷。根据我的经验,在Kubernetes集群中,/var/lib/docker/volumes几乎没有用。

答案 2 :(得分:0)

关于您已编辑的问题。 “ VOLUME”只是容器中的安装点。而且您的容器内的任何更改都将坚持使用您的容器。 因此,当您创建具有相同图像的新容器时,它只会为您创建一个与前一个容器隔离的新卷。 如果要在新容器中使用容器#1的体积,则需要使用“ --volumes-from”选项运行新容器,

docker run -it --volumes-from bfbff0778fe9 --entrypoint=/bin/bash nfnty/arch-bootstrap

我已经做了简单的测试,

root@docker:~/test# cat Dockerfile
FROM alpine
RUN mkdir /test
VOLUME /test
root@docker:~/test# docker build -t test .
root@docker:~/test# docker run -it test sh
/ # cd test
/test # touch hello.txt
/test # exit
root@docker:~/test# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
d11aa6a4ace1        test                "sh"                44 seconds ago      Exited (0) 31 seconds ago                       compassionate_swanson
root@docker:~/test# docker run -it --volumes-from d11aa6a4ace1 alpine sh
/ # ls /test/
hello.txt