美文网首页Dockerk8s
Docker数据卷的使用

Docker数据卷的使用

作者: 文景大大 | 来源:发表于2021-11-18 14:19 被阅读0次

一、分层原理

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

镜像分层示意图

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

  • 所有镜像的目录和文件会被组合成一个大的视图呈现在容器层,如果存在同名的,那么上层会覆盖下层的内容;
  • 增加新的数据会被直接放在最上层的容器层进行保存,镜像层不会被修改;
  • 尝试修改镜像层的数据会先从镜像层将数据copy到容器层,然后进行修改并保存在容器层,镜像层的数据不会被修改;

二、数据卷介绍

  • What?

    Data Volume本质上是宿主机上的文件或者目录,我们可以把它挂载到容器内部的文件系统中,使得宿主机和容器能够共享数据卷中的内容。

  • Why?

    容器中的数据在容器被销毁时也就消失了,在很多业务场景中这是不被允许的,比如数据库、日志系统、数据分析结果等,希望能将容器和存储分离开,容器即便销毁了,存储的数据依然存在。

    多个容器之间也有数据共享的需求,只要还有一个容器存在,共享的数据就不应该被清除;

  • How?

    常见的数据卷挂载主要有两种方式:命令挂载、使用DockerFile挂载,这两种方式都将在下面详细介绍。

三、命令挂载

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,然后在宿主机的挂载目录下发现,文件依然存在,并没有随着容器的移除而删除 。

需要注意的是:

  • 在进行目录挂载的时候,要求宿主机中的文件或路径已经存在,而容器内则不作要求;
  • 已经挂载的路径,本质上是容器把宿主机路径或者文件进步同步copy,而非引用的关系,所以同一目录或者文件是占用两倍存储空间;
  • 可以在容器路径后加上:ro表示该路径容器只允许只读权限,或者加上:rw表示该路径容器拥有读写权限(默认);

指定路径挂载当然存在一定的缺陷,比如我们指定了宿主机的挂载路径,就不利于容器的移植了 ,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,而不是无意义的数字字母组合了。

注意:

  • 数据卷如果被容器使用中是不能被删除的,需要先删除容器后,才可以删除数据卷;
  • 可以通过多个-v同时指定多个挂载路径;

四、共享数据

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

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

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

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指令就是进行数据卷挂载,后面的参数是容器中需要挂载的路径,但是只能进行匿名挂载。

相关文章

网友评论

    本文标题:Docker数据卷的使用

    本文链接:https://www.haomeiwen.com/subject/jswdtrtx.html