Docker存储驱动与套接字简介

Posted 礁之

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker存储驱动与套接字简介相关的知识,希望对你有一定的参考价值。

一、Docker存储驱动

(1)Docker的分层特性

  • Docker容器的启动是依赖于image镜像的,在Docker容器启动前需要先拉取镜像,然后再启动容器,多个容器可以使用同一个镜像动,这些容器都是共用一个镜像,而不是各自将镜像复制一份然后各自独立运行

  • Docker镜像不管是在pull拉取和load加载的时候都是分层拉取或者加载的,从拉取或者加载的过程就可以看出来:

[root@docker ~]# ll
总用量 134228
-rw-------. 1 root root      1264 112 2021 anaconda-ks.cfg
drwxr-xr-x  3 root root      4096 726 21:58 docker
-rw-r--r--  1 root root 137441280 726 21:58 nginx
[root@docker ~]# docker load -i nginx   #可以看到加载的时候都是一步一步加载,并不是一次性加载的
764055ebc9a7: Loading layer [==================================================>]  72.53MB/72.53MB
ace9ed9bcfaf: Loading layer [==================================================>]  64.86MB/64.86MB
48b4a40de359: Loading layer [==================================================>]  3.072kB/3.072kB
c553c6ba5f13: Loading layer [==================================================>]  4.096kB/4.096kB
d97733c0a3b6: Loading layer [==================================================>]  3.584kB/3.584kB
9d1af766c818: Loading layer [==================================================>]  7.168kB/7.168kB
Loaded image: nginx:latest
#可以看到在加载镜像的时候是一层一层加载的,而镜像其实也是这么一层一层存储在磁盘上的
  • 通常一个镜像包含多层:

  • 首先必须明确镜像是只读的。每一层都只读。
  • 在上图上,我们可以看到,在内核之上,最底层首先是一个基础镜像层,这里是一个ubuntu的基础镜像,因为镜像的只读特性,如果我们想要在这个ubuntu的基础镜像上安装一个emacs编辑器(相当于centos的vi编辑器),则只能在基础镜像之上,在构建一层新的镜像层。同样的道理,如果想要在当前的emacs镜像层之上添加一个apache,则只能在其上再构建一个新的镜像层。而这即是镜像的分层特性。

(2)容器读写层的工作原理

  • 上面说了镜像的分层特性,镜像是只读的,包括镜像的每一层都是只读的,而事实上当我们使用镜像启动一个容器的时候,我们是可以在容器里随意读写的,从结果上来看,似乎是与镜像的只读特性相悖。

  • 在上面的图里,在最上层可以看到还有一个读写层。每一个容器在启动的时候,都会基于当前镜像的基础上在镜像的最上层挂载一层读写层,用户对容器的所有操作都是在读写层中完成,一旦容器销毁,这个读写层也会销毁,数据也就丢失了

  • 容器=镜像+读写层。针对读写层的操作,主要基于两种方式,写时复制和用时分配。

-写时复制:

写时复制是所有驱动都用到的技术。COW(Copy On Write的缩写),表示只有在写的时候才去复制,这是针对已有文件的修改场景。例如:基于一个镜像启动多个容器,如果为每个容器都去分配一个镜像一样的文件系统,那么会占用大量的磁盘空间,那么容器的轻量级优势也就没有了,而COW技术可以让所有的容器共享镜像的文件系统,所有的数据都从镜像中读取,只有容器要对文件进行写操作时,容器才会从镜像里把要写的文件复制到自己的文件系统中进行修改,所以无论有多少个容器共享一个镜像,所做的写操作都是从镜像中复制到自己的文件系统中的副本上进行,并不会修改镜像中的源文件,并且多个容器操作一个相同的文件,就会在多个容器的文件系统中生成一个对应的文件副本,每个容器修改的都是自己的文件副本,相互不影响。使用COW可以有效的提高磁盘的利用率

-用时分配:

用时分配是用在原本没有这个文件的场景,只有在要新写入一个文件时才会分配空间,这样可以提高存储资源的利用率。例如:启动一个容器,并不会为这个容器预分配一些磁盘空间,而是在有新的文件写入时,才会按需分配新空间

(3)Docker存储驱动

  • Docker提供了多种存储驱动来实现不同的方式存储镜像,常用的有:
  • AUFS
  • OverlayFS
  • Devicemapper
  • Btrfs
  • ZFS
  • 现在最常用的就是OverlayFS存储驱动,现在已经更新到了Overlay2

-AUFS

AUFS(AnotherUnionFS)是一种Union FS,是文件级的存储驱动。AUFS是一个能透明覆盖一个或多个现有文件系统的层状文件系统,把多层合并成文件系统的单层表示。简单来说就是支持将不同目录挂载到同一个虚拟文件系统下的文件系统。这种文件系统可以一层一层地叠加修改文件。无论底下有多少层都是只读的,只有最上层的文件系统是可写的。当需要修改一个文件时,AUFS创建该文件的一个副本,使用CoW将文件从只读层复制到可写层进行修改,结果也保存在可写层。在Docker中,底下的只读层就是image镜像,可写层就是Container容器。结构如下图所示:

-OverlayFS

Overlay是Linux内核3.18后支持的,也是一种Union FS,和AUFS的多层不同的是Overlay只有两层:一个upper文件系统和一个lower文件系统,分别代表Docker的镜像层和容器层。当需要修改一个文件时,使用CoW将文件从只读的lower复制到可写的upper进行修改,结果也保存在upper层。在Docker中,底下的只读层就是image,可写层就是Container。目前最新的OverlayFS为Overlay2。

-Devicemapper

Device mapper是Linux内核2.6.9后支持的,提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的管理策略。前面讲的AUFS和OverlayFS都是文件级存储,而Device mapper是块级存储,所有的操作都是直接对块进行操作,而不是文件。Device mapper驱动会先在块设备上创建一个资源池,然后在资源池上创建一个带有文件系统的基本设备,所有镜像都是这个基本设备的快照,而容器则是镜像的快照。所以在容器里看到文件系统是资源池上基本设备的文件系统的快照,并没有为容器分配空间。当要写入一个新文件时,在容器的镜像内为其分配新的块并写入数据,这个叫用时分配。当要修改已有文件时,再使用CoW为容器快照分配块空间,将要修改的数据复制到在容器快照中新的块里再进行修改。Device mapper 驱动默认会创建一个100G的文件包含镜像和容器。每一个容器被限制在10G大小的卷内,可以自己配置调整。结构如下图所示:

-常用存储驱动对比

存储驱动特点优点缺点适用场景
AUFS联合文件系统、未并入内核主线、文件级存储作为docker的第一个存储驱动,已经有很长的历史,比较稳定,且在大量的生产中实践过,有较强的社区支持有多层,在做写时复制操作时,如果文件比较大且存在比较低的层,可能会慢一些大并发但少IO的场景
overlayFS联合文件系统、并入内核主线、文件级存储只有两层不管修改的内容大小都会复制整个文件,对大文件进行修改显示要比小文件消耗更多的时间大并发但少IO的场景
Devicemapper并入内核主线、块级存储块级无论是大文件还是小文件都只复制需要修改的块,并不是整个文件不支持共享存储,当有多个容器读同一个文件时,需要生成多个复本,在很多容器启停的情况下可能会导致磁盘溢出适合io密集的场景
Btrfs并入linux内核、文件级存储可以像devicemapper一样直接操作底层设备,支持动态添加设备不支持共享存储,当有多个容器读同一个文件时,需要生成多个复本不适合在高密度容器的paas平台上使用
ZFS把所有设备集中到一个存储池中来进行管理支持多个容器共享一个缓存块,适合内存大的环境COW使用碎片化问题更加严重,文件在硬盘上的物理地址会变的不再连续,顺序读会变的性能比较差适合paas和高密度的场景

-AUFS VS OverlayFS

AUFS和Overlay都是联合文件系统,但AUFS有多层,而Overlay只有两层,所以在做写时复制操作时,如果文件比较大且存在比较低的层,则AUSF可能会慢一些。而且Overlay并入了linux kernel mainline,AUFS没有。目前AUFS已基本被淘汰

OverlayFS VS Device mapper

OverlayFS是文件级存储,Device mapper是块级存储,当文件特别大而修改的内容很小,Overlay不管修改的内容大小都会复制整个文件,对大文件进行修改显然要比小文件要消耗更多的时间,而块级无论是大文件还是小文件都只复制需要修改的块,并不是整个文件,在

这种场景下,显然device mapper要快一些。因为块级的是直接访问逻辑盘,适合IO密集的场景。而对于程序内部复杂,大并发但少IO的场景,Overlay的性能相对要强一些。

二、Docker套接字介绍

作用: 可以使不同主机连接(使用)不同主机的docker

******查看Docker状态
[root@docker ~]# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: active (running) since 一 2021-07-26 22:00:11 CST; 37min ago
     Docs: https://docs.docker.com
 Main PID: 1326 (dockerd)
   Memory: 168.9M
   CGroup: /system.slice/docker.service
           └─1326 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

726 22:00:10 docker dockerd[1326]: time="2021-07-26T22:00:10.860859981+08:00" level=info msg="Loading containers: start."
726 22:00:11 docker dockerd[1326]: time="2021-07-26T22:00:11.038497116+08:00" level=info msg="Default bridge (docker0) is a...ddress"
726 22:00:11 docker dockerd[1326]: time="2021-07-26T22:00:11.073211819+08:00" level=info msg="Loading containers: done."
726 22:00:11 docker dockerd[1326]: time="2021-07-26T22:00:11.084423373+08:00" level=info msg="Docker daemon" commit=481bc77...18.09.6
726 22:00:11 docker dockerd[1326]: time="2021-07-26T22:00:11.084469997+08:00" level=info msg="Daemon has completed initialization"
726 22:00:11 docker dockerd[1326]: time="2021-07-26T22:00:11.101030654+08:00" level=info msg="API listen on /var/run/docker.sock"
726 22:00:11 docker systemd[1]: Started Docker Application Container Engine.
726 22:03:07 docker dockerd[1326]: time="2021-07-26T22:03:07.581931947+08:00" level=warning msg="Error getting v2 registry:...aders)"
726 22:03:07 docker dockerd[1326]: time="2021-07-26T22:03:07.581957043+08:00" level=error msg="Not continuing with pull aft...aders)"
726 22:03:07 docker dockerd[1326]: time="2021-07-26T22:03:07.581994482+08:00" level=error msg="Handler for POST /v1.39/imag...aders)"
Hint: Some lines were ellipsized, use -l to show in full.
******查看docker版本
[root@docker ~]# docker version
Client:                              #客户端引擎社区版
 Version:           18.09.6          #版本
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        481bc77156
 Built:             Sat May  4 02:34:58 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community     #服务端引擎
 Engine:
  Version:          18.09.6           #版本
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       481bc77
  Built:            Sat May  4 02:02:43 2019
  OS/Arch:          linux/amd64
  Experimental:     false
#docker是一个C/S架构,在执行docker的指令的时候,会默认连接到自己本机的docker -deamon进程
******停止掉docker进程
[root@docker ~]# systemctl  stop docker
[root@docker ~]# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
   Active: inactive (dead) since 一 2021-07-26 22:42:49 CST; 4s ago
   Docs: https://docs.docker.com
   Process: 1326 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock (code=exited, status=0/SUCCESS)
   Main PID: 1326 (code=exited, status=0/SUCCESS)

  726 22:00:11 docker dockerd[1326]: time="2021-07-26T22:00:11.084423373+08:00" level=info msg="Docker daemon" commit=481bc77...18.09.6
  726 22:00:11 docker dockerd[1326]: time="2021-07-26T22:00:11.084469997+08:00" level=info msg="Daemon has completed initialization"
  726 22:00:11 docker dockerd[1326]: time="2021-07-26T22:00:11.101030654+08:00" level=info msg="API listen on /var/run/docker.sock"
  726 22:00:11 docker systemd[1]: Started Docker Application Container Engine.
  726 22:03:07 docker dockerd[1326]: time="2021-07-26T22:03:07.581931947+08:00" level=warning msg="Error getting v2 registry:...aders)"
  726 22:03:07 docker dockerd[1326]: time="2021-07-26T22:03:07.581957043+08:00" level=error msg="Not continuing with pull aft...aders)"
  726 22:03:07 docker dockerd[1326]: time="2021-07-26T22:03:07.581994482+08:00" level=error msg="Handler for POST /v1.39/imag...aders)"
  726 22:42:49 docker systemd[1]: Stopping Docker Application Container Engine...
  726 22:42:49 docker dockerd[1326]: time="2021-07-26T22:42:49.280932423+08:00" level=info msg="Processing signal 'terminated'"
  726 22:42:49 docker systemd[1]: Stopped Docker Application Container Engine.
  Hint: Some lines were ellipsized, use -l to show in full.
[root@docker ~]# docker version   #再次查看docker版本号,发现server端没有了
Client:
 Version:           18.09.6
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        481bc77156
 Built:             Sat May  4 02:34:58 2019
 OS/Arch:           linux/amd64
 Experimental:      false
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?  #显示无法连接Docker daemon,连接的方式是基于文件套接字连接

#客户端使用套接字连接,不需要监听任何端口,只需要读取/var/run/docker.sock这个文件
[root@docker ~]# ll /var/run/docker.sock 
srw-rw---- 1 root docker 0 726 22:00 /var/run/docker.sock

#默认是监听本地的套接字文件,也可以使用网络套接字,需要修改启动文件
[root@docker ~]# vim /lib/systemd/system/docker.service  
。。。。。。
 13 # for containers run by docker
 14 ExecStart=/usr/bin/dockerd -H fd://  -H 0.0.0.0:2375 --containerd=/run/containerd/containerd.sock  #配置成监听网络接口
 15 ExecReload=/bin/kill -s HUP $MAINPID
 16 TimeoutSec=0
 17 RestartSec=2
。。。。。。
#保存退出
[root@docker ~]# systemctl daemon-reload
[root@docker ~]# systemctl start docker
[root@docker ~]# netstat -anpt | grep 2375   #查看端口,成功监听
tcp6       0      0 :::2375                 :::*                    LISTEN      16356/dockerd 

#docker的网络套接字就配置完成,客户端就可以连接2375端口,连接docker-daemon,服务端就是开启端口,等着客户端进行访问
[root@docker ~]# docker -H 192.168.100.202 version   #使用本机或者另外一台安装docker的机器上运行,version是命令,这个命令就是docker命令,例如:docker images 就可以写成docker -H 192.168.100.202:2375 images,实现不同主机访问docker
Client:
 Version:           18.09.6
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        481bc77156
 Built:             Sat May  4 02:34:58 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.6
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       481bc77
  Built:            Sat May  4 02:02:43 2019
  OS/Arch:          linux/amd64
  Experimental:     false
[root@docker ~]# docker -H 192.168.100.202:2375 version
Client:
 Version:           18.09.6
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        481bc77156
 Built:             Sat May  4 02:34:58 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.6
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       481bc77
  Built:            Sat May  4 02:02:43 2019
  OS/Arch:          linux/amd64
  Experimental:     false
[root@docker ~]# docker -H 192.168.100.202:2375 images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              4cdc5dd7eaad        2 weeks ago         133MB
#docker在开启网络套接字,默认是没有任何验证的,需要安全配置,否则会很危险,生产中也不会使用网络套接字来管理所有的docker客户端,默认使用本地的文件套接字管理自己的docker服务端,如果需要管理所有的docker,可以借助K8S平台进行管理

以上是关于Docker存储驱动与套接字简介的主要内容,如果未能解决你的问题,请参考以下文章

有容云-原理Docker存储驱动之AUFS

DOCKER存储驱动之DEVICE MAPPER简介

Docker存储驱动之Device Mapper简介

Docker存储驱动之Btrfs简介

Docker存储驱动之ZFS简介

docker镜像与容器的联系存储驱动