Dockerk8s

Docker数据卷的使用

2021-11-18  本文已影响0人  文景大大

一、分层原理

在前面介绍过 ,镜像是一层层叠加而来,是只读不可修改的。最上面的一层称为“容器层”,是由镜像启动时,被添加的一层,我们的任何修改都会被记录在该容器层,而其它部分称为“镜像层”,都是只读不可修改的。镜像层的最下面我们称之为基础镜像(Base),大致的结构示意图如下所示。

镜像分层示意图

分层的好处就是可以共享资源,比如多个镜像都由某个Base镜像构建而来,那么在下载这些镜像的时候,Base镜像就可以共享使用,只需要下载一份,只需要保存一份Base镜像即可。除此之外,分层所体现的最大特性就是Copy-on-Write

二、数据卷介绍

三、命令挂载

3.1 指定路径挂载

所谓指定路径,是指同时指定了宿主机和容器内的挂载路径。

docker run -d -p 80:80 --name nginx01 -v E:\docker\nginx:/usr/nginx nginx

如上命令是在创建并启动容器的时候就进行目录的挂载,-d表示后台启动,-p 80:80表示绑定宿主机和容器的端口映射,--name nginx01表示指定新建的容器名称指定为nginx01,-v local_path:container_path表示挂载目录,将宿主机的路径local_path和容器内的路径container_path镜像挂载。

执行完成后,我们可以进入容器进行验证:

# pwd
/
# ls
bin   dev                  docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   media  opt  root  sbin  sys  usr
# cd usr
# ls
bin  games  include  lib  libexec  local  nginx  sbin  share  src
# cd nginx
# ls
#

可以看到,容器内部的/usr/nginx目录已经存在,但是里面没有任何内容。现在我们在宿主机上或者在容器内的挂载目录内创建一个文件,在另外一边都能同步看到。

# pwd
/
# ls
bin   dev                  docker-entrypoint.sh  home  lib64  mnt  proc  run   srv  tmp  var
boot  docker-entrypoint.d  etc                   lib   media  opt  root  sbin  sys  usr
# cd usr
# ls
bin  games  include  lib  libexec  local  nginx  sbin  share  src
# cd nginx
# ls
# ls
readme.txt
# cat readme.txt
hello docker volume!#

我们此时将容器删除:docker rm nginx01,然后在宿主机的挂载目录下发现,文件依然存在,并没有随着容器的移除而删除 。

需要注意的是:

指定路径挂载当然存在一定的缺陷,比如我们指定了宿主机的挂载路径,就不利于容器的移植了 ,A宿主机有这个挂载路径,B宿主机也许就没有 。

3.2 匿名挂载

docker run -d -p 80:80 --name nginx2 -v /usr/nginx02 nginx

该命令与指定目录挂载的区别是-v /usr/nginx02只是指定了容器内的挂载路径,并未指定宿主机的挂载路径。我们可以通过docker inspect name来查看容器的详细信息得到具体宿主机的挂载路径:

"Mounts": [
    {
        "Type": "volume",
        "Name": "592c56295f0200cb62b5f226cba1f53c77e45b48a95c77b6ce791c9b05696cc7",
        "Source": "/var/lib/docker/volumes/592c56295f0200cb62b5f226cba1f53c77e45b48a95c77b6ce791c9b05696cc7/_data",
        "Destination": "/usr/nginx02",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
]

如上Source中的路径就是宿主机上的挂载路径,Destination是容器内的挂载路径。我们注意到卷名目录是一串无意义的数字字母组合,因此称为匿名挂载。

问题:以上挂载路径在windows系统的哪里尚未找到,有知道的可以帮忙补充下。

3.3 具名挂载

所谓具名就是指给无意义的数据卷起名字,挂载的格式和指定路径挂载一致 :

docker run -d -p 80:80 --name nginx3 -v nginx_volume:/usr/nginx03 nginx

此时 ,数据卷的名称就是我们指定的nginx_volume,而不是无意义的数字字母组合了。

注意:

四、共享数据

在前面的例子中,我们已经实现了宿主机挂载路径和容器内挂载路径的数据共享,下面就数据共享进行更深一步地探讨。

场景一:多个容器组成的集群需要共享宿主机的数据。

按照如上的使用说明,我们同时为多个容器挂载到宿主机的同一目录或者文件即可:

docker run -d -p 80:80 --name nginx01 -v E:\docker\nginx:/usr/nginx nginx
docker run -d -p 81:81 --name nginx02 -v E:\docker\nginx:/usr/nginx nginx
docker run -d -p 82:82 --name nginx03 -v E:\docker\nginx:/usr/nginx nginx

但是有一个缺点,一旦我们要修改宿主机的挂载目录,需要对每一个容器的挂载关系进行修改,显然不方便。此时我们就需要抽象一层容器出来,使得只有该容器和宿主机的挂载点绑定,其它容器和该容器绑定,这种容器我们称之为“数据卷容器”,Volume Container,简称VC容器。

docker create --name vc_data -v volume_name:container_path image_name
docker run -d -p 80:80 --name nginx01 --volumes-from  vc_data nginx
docker run -d -p 81:81 --name nginx02 --volumes-from  vc_data nginx
docker run -d -p 82:82 --name nginx03 --volumes-from  vc_data nginx

如此,nginx01、nginx02、nginx03这三个容器就继承了vc_data数据卷容器的数据卷信息,使得它们和宿主机的挂载路径绑定了对应关系。随后只要修改vc_data的挂载关系,nginx01~nginx03就能自动更改,体现了编程领域的继承和解耦的优势。

场景二:多个容器组成的集群相互之间共享数据

这种场景就是不涉及宿主机的文件了,容器之间的数据不需要和宿主机进行共享。我们在创建镜像的时候就把数据封装到了镜像里面,并且建立了数据卷。

FROM busybox:latest
ADD readme.md /usr/file
VOLUME /usr/file

如上的dockerfile指定了数据卷就是容器的usr/file目录,然后基于该dockerfile构建镜像并创建容器:

docker build -t new_image .
docker create --name vc_data new_image

如此新创建的vc_data就是容器卷镜像,它不需要运行,只是共享数据而已。

docker run -d -p 80:80 --name nginx01 --volumes-from  vc_data nginx
docker run -d -p 81:81 --name nginx02 --volumes-from  vc_data nginx
docker run -d -p 82:82 --name nginx03 --volumes-from  vc_data nginx

如此,就能实现容器之间数据卷的共享。需要注意的是,只要任何一个容器仍然存在,那么该数据卷就不会被删除,只有当所有使用该数据卷的容器都删除了,数据卷才会被删除。

五、DockerFile挂载

在后面的内容中我们会介绍Dockerfile的使用,其中也可以在新镜像的制作时就进行数据卷的挂载,比如:

FROM java:8
VOLUME ["/tmp","/home/docker/demo"]
...

其中,VOLUME指令就是进行数据卷挂载,后面的参数是容器中需要挂载的路径,但是只能进行匿名挂载。

上一篇下一篇

猜你喜欢

热点阅读