Docker 存储选型这些年我们遇到的坑_第1页
Docker 存储选型这些年我们遇到的坑_第2页
Docker 存储选型这些年我们遇到的坑_第3页
Docker 存储选型这些年我们遇到的坑_第4页
Docker 存储选型这些年我们遇到的坑_第5页
已阅读5页,还剩14页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

-19-Docker存储选型,这些年我们遇到的坑随着Docker容器技术的不断进展和业内对Docker的使用不断深化,大家已经不再满意于对Docker的基本使用。把玩Docker多年的老司机应当或多或少都会遇到过一些Docker存储方面的问题,比如由于宿主机文件系统和Docker存储类型不兼容引起的问题,或者使用AUFS消失文件复制慢等问题,存储问题每次遇到都要心里一紧。

随着Docker容器技术的不断进展和业内对Docker的使用不断深化,大家已经不再满意于对Docker的基本使用。把玩Docker多年的老司机应当或多或少都会遇到过一些Docker存储方面的问题,比如由于宿主机文件系统和Docker存储类型不兼容引起的问题,或者使用AUFS消失文件复制慢等问题,存储问题每次遇到都要心里一紧。

Docker存储类的问题在排查上往往比较简单,有过Docker存储类问题排查阅历的同学应当都有体会。每当遇到此类的问题笔都有一股想找Docker公司理论的冲动,不是说好的'buildoncerunanywhere'吗?

笔者自己所在的团队也曾数次遇到关于Docker存储的问题,每次团队内的成员基本都是避之不及,生怕会由自己处理(怕掉坑里)。为此笔者特地理了一下Docker存储类的问题的简单点,发觉这里面很大一部分其实是由于问题处理人员对Docker的存储类型、存储原理不了解造成的,为此我们特地整理了一份Docker选型方面的避坑指南,供大家参考,盼望可以关心到大家。

Docker存储概述

我们知道,每个Docker容器里面都有一个自己的文件系统,Docker在运行容器时需要进行文件系统的创建,这样rootfs才能进行挂载。

Bootfs也称引导文件系统,位于Docker镜像和Docker容器的最底层。bootfs中主要包含两个部分:bootloader和kernel,bootloader用于引导加载内核,当内核加载到内存中后bootfs的使命就完成了,接下来bootfs会被卸载掉。rootfs中包含了一些linux中标准的名目和文件,包括:/dev/设备文件名目、/proc/进程信息名目、/bin/二进制文件名目、/etc/配置文件名目等。

众所周知,Docker存储的核心是镜像的分层机制,镜像分层的一大好处是镜像之间可以进行继承,也正是由于这个特性我们可以借助基镜像定制化的构建我们需要的应用镜像。

Docker官方在版本1.10时引入一个新的可寻址的存储模型,了解过Docker存储这方面的同学应当知道在Docker1.10之前Docker镜像的管理是使用的随机的UUID管理,Docker1.10之后已经使用平安内容hash取代了随机UUID进行镜像的管理。同时,考虑到已经有许多用户在使用UUID的镜像管理方式,Docker官方特地针对这个改动供应了迁移工具,关心大家将已经存在的镜像迁移到新的模型之上。

我们知道,一个有众多版本的镜像的全部镜像占据的空间可能比单个版本的镜像占用的空间多不了多少(比如一个nginx镜像有500MB,依据配置的不同我们保存了10个版本,10个版本占用的空间一般和一个nginx镜像占用的空间接近,远低于10个镜像空间的总和)。多个版本占用的空间之所以没有明显增加是由于Docker容器、镜像可以共享底层的基础文件系统层,虽然镜像的个数许多,但是他们占据的共享镜像层在磁盘中只存在一份,每个容器只需要在自己的最上层加上一个自己独有的可读可写层就可以正常使用了,由于这种存储机制的存在大大提高了Docker镜像存储的效率。这种模式的主要机制就是分层模型将不同的名目挂载到了同一个虚拟文件系统之上,通过下面这个图可以很好的理解这种模式。

上文中我们提到docker的镜像是分层的,但我们没有说这部分的功能详细是由哪一部分实现的。其实不仅分层镜像,包括每个Docker容器的可读写层都是由Docker的存储方式负责管理的。

接触容器比较早的同学可能还记得,Docker在最初的时候只能在支持AUFS的文件系统的操作系统上运行,而当时在众多操作系统中Ubuntu已经领先供应了对AUFS的支持,因此最开头玩Docker的同学使用的linux发行版都是Ubuntu系列的发行版。

但是由于AUFS未能加入Linux内核,成为linux发行版的标配,因此为了寻求兼容性和扩展性,Docker在内部通过graphdriver这样一种机制以一种可以扩展的方式实现了对不同文件的系统的兼容(实际使用中可能发觉有些版本还是会存在一些兼容性的问题)。

Docker目前支持的驱动类型包括:AUFS、Devicemapper、Btrfs、OverlayFS和ZFS(较新),这些驱动存在一个共同点,那就是都使用了写时复制技术。下面我们逐个看下这种存储驱动的特性以及在使用中可能会遇到的问题。

AUFS存储驱动

1.UnionFileSystem

UnionFS(UnionFileSystem简称)是一种为Linux、FreeBSD等操作系统而设计的,可以把其他文件系统联合到一个挂载点的文件系统服务。

简洁说来联合文件系统就是将不同的名目挂载到同一个虚拟机文件系统下的文件系统。这种文件系统的一大特点就是可以一层层的叠加修改文件,除了最上面的一层之外无论底下有多少层都是只读的,只有最上层的文件系统是可以写的。

UnionFS使用分支(branch)对不同文件系统的文件(包含名目)进行掩盖,从而最终形成一个单一的文件系统,也就是我们直接操纵的文件系统。UnionFS使用的这些分支要么是只读的,要么是读写的,分支的这种特性打算了当我们对虚拟后的联合文件系统中写入数据的时候,数据被写到了一个新的文件中。这样看来我们好像可以操作这个虚拟文件系统中的任何的文件,但其实我们并未转变原来的文件,导致这种状况消失的缘由是UnionFS使用了写时复制(copy-on-write)这样一种资源管理技术。

写时复制也称隐式共享(此名称可能较少见),写时复制是一种可以对可修改资源实现高效复制的资源管理技术。它的核心的设计思想是,假如一个数据资源是重复的,没有做过任何的修改,这个时候不需要创建新的资源,而是让新旧实例都去共享这仅有一份的资源。当需要对资源进行数据的增加或者修改的时候才会进行新资源的创建。从上面的写时复制的原理中我们即可看出,通过这种资源共享的方式我们可以省掉对未修改资源的复制,从而为我们带来效率的提升。

2.AUFS

AUFS全称为AdvancedMulti-LayeredUnificationFilesystem,是一种联合文件系统,是一种文件级的存储驱动,出于对牢靠性和性能的考虑,AUFS对UnionFS1.x进行了整个的重写,并且在重写过程中还引入了一些新的功能特性,比如对于可写的分支添加了负载均衡的功能。不仅仅是AUFS借鉴UnionFS,UnionFS也会去借鉴AUFS,比如UnionFS2.x中借鉴了AUFS的一些实现。

有些同学可能会问,存储驱动类型这么多,为什么Docker最开头选择AUFS作为自己的存储驱动?笔者个人认为是由于AUFS具备的以下几个优势:快速启动容器、高效利用存储、高效利用内存。

当我们需要对一个文件进行修改时,AUFS会为目的文件创建一个文件副本,详细是从包含该文件的只读层使用写时复制技术将文件复制到最上面的可写层。需要留意的是,当我们修改完文件之后修改后的文件是保存在最上层的可写层的,下面的只读层的文件并未被修改。

3.Docker对AUFS的使用

在Docker体系中,我们熟知的最上层的读写层就是容器,除最上层之外的下面的那些层就是镜像。

4.AUFS避坑

了解AUFS存储驱动的优势和劣势可以关心我们更好的对存储驱动进行选型,同时也可在很大程度上关心我们排查AUFS存储驱动方面相关的问题。

好,我们先看下AUFS作为Docker存储驱动的优势,以便选择更合适的使用场景:

(1)得益于AUFS高效的名目挂载机制,Docker可以很快的创建容器。AUFS的读写效率很高,和直接在Docker容器所在宿主机上的读写接近。和虚拟服务器相比,AUFS读写性能优于KVM,包括挨次读写和随机读写两个方面。除此磁盘的高效使用之外,Docker的AUFS存储驱动也可以对内存进行特别高效的使用。

(2)相比一些消失较晚的Docker存储驱动,DockerAUFS存储驱动性能相对比较稳定,并且AUFS目前已经有许多的生产部署实践,另外AUFS在社区生态方面也得到大量的支持。

下面我们再看下AUFS作为Docker存储驱动存在的坑:

(1)AUFS是Docker第一个支持的存储驱动,但AUFS目前仍未加入linux系统的内核主线,比如RedHat系列(包括CentOS)目前还无法直接使用AUFS。

(2)AUFS目前不支持重命名的系统调用,这个会导致我们在执行拷贝和解除连接时失败。

(3)我们知道AUFS文件系统中每个源名目都会对应一个分支文件的挂载过程其实就是对不同分支的一个联合操作,当消失相同内容的不同分支时会进行上下层的掩盖。但是当我们写入大文件的时候,比如大的存储日志信息的文件或者存储数据库数据库的文件,动态挂载多个路径的存在会使分支越来越多,进而会导致文件查找的性能越来越差,尤其是当文件存在于较低的层时,问题会更加严峻。

小结:AUFS存储驱动建议在大并发但少I/O的场景下进行使用。

Devicemapper

1.DeviceMapper原理

部署Docker环境的时候一般都会要求Linux内核版本最低为3.10,好像Docker运行需要的存储驱动是从linux内核3.10这个版本才进行引入的,但实际早在linux内核版本2.6的时候DeviceMapper就已经被引入。

DeviceMapper作为内核的一部分主要供应了规律卷管理和通用设备映射的功能,为了实现系统中的块设备管理供应了一个高度模块化的内核的架构。

在深化了解DeviceMapper之前我们需要先了解下DeviceMapper中三个比较重要的概念:MappedDevice、MappingTable和TargetDevice。

MappedDevice并不是一个实际的设备,并没有实际的物理硬件和它一一对应,相反MappedDevice是一个规律上的抽象设备,简洁说来,可以将其理解成为内核向外供应的规律设备。MappedDevice通过另一个对象MappingTable和TargetDevice建立映射关系。

MappingTable中包含MappedDevice规律的起始地址、地址范围以及TargetDevice代表的物理设备的地址偏移量和Target的类型信息,需要留意的是地址和偏移量单位为扇区,即512字节。

TargetDevice简洁说来就是MappedDevice这个规律设备所映射到的一个物理设备。

DeviceMapper是块级别的存储驱动,全部的操作都是对存储块进行直接的操作,这方面和上文中讲的AUFS不同(AUFS是文件级的存储,全部的操作都是对文件进行直接的操作)。

在使用DeviceMapper时,DeviceMapper会先在块设备上创建一个资源池,然后接下来会在新建的资源池上添加一个没有文件系统的基本设备,我们全部的容器镜像都是这个设备的快照,我们的Docker容器是镜像的快照。因此我们在Docker容器中看到的文件系统系统其实是DeviceMapper资源池上基本设备上的文件系统的快照,实际上并没有为我们的Docker容器进行空间的安排。

理解DeviceMapper的工作机制,还需要明白用时安排。用时安排是指,当我们需要写入一个文件时,我们需要为新文件安排新的存储块并,安排好存储块后才能进行数据的写入。

当我们需要去修改容器中已经存在的文件时,这个时候DeviceMapper借助写时复制技术为容器安排存储块空间,然后DeviceMapper将需要修改的数据拷贝到容器快照中前面新建的块里面,之后才会对文件中的数据进行修改。

值得一提的是,DeviceMapper存储驱动默认会创建一个100GB文件,包含Docker容器和Docker镜像,需要留意的默认状况下每个容器的大小都被限制在10GB的卷以内,但可以进行自定义的设置,详细结构如下图:

另外Docker存储驱动的信息可以通过命令dockerinfo或者dmsetupls进行查看:

[root@localhost~]#dockerinfo

Containers:11

Running:0

Paused:0

Stopped:11

Images:6

ServerVersion:1.10.3

StorageDriver:devicemapper

PoolName:docker-8:3-404820673-pool

PoolBlocksize:65.54kB

BaseDeviceSize:10.74GB

BackingFilesystem:xfs

Datafile:/dev/loop0

Metadatafile:/dev/loop1

DataSpaceUsed:12.51GB

DataSpaceTotal:107.4GB

DataSpaceAvailable:82.06GB

MetadataSpaceUsed:10.18MB

MetadataSpaceTotal:2.147GB

MetadataSpaceAvailable:2.137GB

UdevSyncSupported:true

DeferredRemovalEnabled:false

DeferredDeletionEnabled:false

DeferredDeletedDeviceCount:0

Dataloopfile:/var/lib/docker/devicemapper/devicemapper/data

WARNING:Usageofloopbackdevicesisstronglydiscouragedforproductionuse.Eitheruse`storage-optdm.thinpooldev`oruse`storage-optdm.no_warn_on_loop_devices=true`tosuppressthiswarning.

Metadataloopfile:/var/lib/docker/devicemapper/devicemapper/metadata

LibraryVersion:1.02.107-RHEL7(2022-06-09)

ExecutionDriver:native-0.2

LoggingDriver:journald

Plugins:

Volume:local

Network:nullhostbridge

KernelVersion:3.10.0-327.36.1.el7.x86_64

OperatingSystem:CentOSLinux7(Core)

OSType:linux

Architecture:x86_64

NumberofDockerHooks:2

CPUs:4

TotalMemory:1.781GiB

Name:localhost.localdomain

ID:V7HM:XRBY:P6ZU:SGWK:J52L:VYOY:UK6L:TR45:YJRC:SZBS:DQRF:CFP5

WARNING:bridge-nf-call-iptablesisdisabled

WARNING:bridge-nf-call-ip6tablesisdisabled

Registries:docker.io(secure)

[root@localhost~]#dmsetupls

docker-8:3-404820673-pool(253:0)

2.DeviceMapper避坑

(1)DeviceMapper优势

DeviceMapper的写时复制机制的最小操作单元为64KB,块级无论是大文件还是小文件都只需要复制需要修改的块,并不复制整个文件,相比aufs存储驱动和overlay存储驱动的整个文件复制DeviceMapper的效率更高。

相比上文中我们说过的AUFS存储驱动,DeviceMapper在文件系统兼容性方面较好,另外DeviceMapper存储驱动只需要一个文件进行存储,基本不会占用文件系统的inode。

(2)DeviceMapper避坑

在内存使用方面,以DeviceMapper作为存储驱动时,启动多少个容器就需要复制多少份文件到内存中,由于DeviceMapper不支持共享存储,当有多个容器需要读同一个文件的内容时,需要生成多个该文件的副本,在较多的容器进行启动、停止的时候可能会消失磁盘溢出的状况。因此假如是容器密度高的业务场景下尽量不要部署到单台主机上。

每个容器每次在写数据时都需要占用一个新的块,由于每个存储块都需要借助存储池进行安排,且写的文件比较稀疏,尽管DeviceMapper的I/O利用率很高,但由于额外增加了VFS开销导致性能不好。在选择存储类型时需要着重留意下这一点,剧烈建议依据自己的业务场景进行压测后再进行选择。

在实际使用中,假如我们为每个容器都进行块设备的安排,当启动多个容器时数据会从磁盘被多次加载到内存中,因此在这种场景下时内存消耗较大,在选型时需要留意。

当选用的宿主机为RHEL系列(包含CentOS)时,需要留意DeviceMapper是RHEL系列下的默认的存储驱动,配置方式分为两种模式:loop-lvm和direct-lvm。其中loop-lvm是默认的模式,loop-lvm使用操作系统的层面的离散文件来构建精简池。一般状况下生产环境推举使用direct-lvm模式,不建议使用默认的loop-lvm模式,经实际测试loop-lvm的性能很难达到生产环境的要求

小结:DeviceMapper存储驱动更适合在I/O密集的场景下进行使用。

OverlayFS文件系统

1.Overlay原理

Overlay存储驱动的设计和AUFS特别相像,也是一种联合文件系统,同时也是一种文件级别的存储驱动,但和AUFS不同的是Overlay只有两层(一个是upperdir,另一个是lowerdir,从二者的名字也可看出,upperdir代表的是我们的容器层,lowerdir层代表的是我们的镜像层),而AUFS有多层。相比AUFSOverlay存储驱动进入linux较晚(Linux内核3.18之后才进行支持)。

当需要对文件进行修改时,需要借助写时复制从只读的lowerdir层复制到可读写的upperdir层,然后再在upperdir层中对文件进行修改,修改完成后的文件最终也是保存在组上面的upper层中。

2.Ovrelay避坑

在说Overlay使用之前我们先看下它的优点,看下它适合的业务场景都有哪些。

(1)从性能上来看,Overlay存储驱动要比DeviceMapper更好,速度更快。在某些状况下Overlay的速度也比Btrfs存储驱动快。由于Overlay只有两层,AUFS有多层,因此Overlay在速度上也比AUFS要快,削减操作延时。

(2)Overlay支持页缓存的共享,这样在多个容器在访问同一个文件时可以共享一个页缓存,从而提高内存使用效率。

下面我们再看下Overlay在使用时需要留意的问题,留意避坑。

(1)Overlay存储驱动消失较晚,目前生产环境部署的阅历相对较少,实际使用中需要解决的问题可能较多。

(2)由于Overlay存储驱动是文件级的,因此在对文件进行第一次的操作时需要将目标文件拷贝至最上面的读写层。

(3)和其他的存储驱动相比,Overlay消耗inode较多(我们有个容器云曾经消失过此种状况),尤其是当我们环境中镜像和容器较多时可能会触发这个问题。为了解决这个问题,一般的建议方式是将名目/var/lib/docker直接挂到某个单独的文件系统中,这样在肯定程度上可以削减其他的文件对inode的占用。

上面提到的解决方式只是最常用的一种,除了这种方式,我们还有其他的解决方式,如Overlay版本更换为Overlay2,Overlay2中已经解决了这个问题,在我们不再具体描述。

(4)除了上面说到的这些问题,Overlay还存在POSIX的标准问题。Overlay的部分操作目前还不符合POSIX的标准。

(5)最终需要留意的是Overlay不支持rename系统调用,因此假如涉及到'copy'、'unlink'的操作会消失失败的状况。

小结:Overlay存储适合大并发但少I/O的场景。

Btrfs文件系统

1.Btrfs原理

Btrfs文件系统也称B-tree文件系统或者B-treeFS,Btrfs是一种支持写入复制的文件系统,由着名公司Oracle进行研发,第一个稳定版本于2022年进行发布。Btrfs文件系统的目标是取代linux中的ext3文件系统。

Btrfs被许多人称为下一代的写时复制文件系统,和Overlay相像也是基于文件级别的存储,目前Btrfs已经并入linux内核。

和前面我们讲到的DeviceMapper类似,Btrfs可以对底层的设备进行直接的操作。

Btrfs中有两个重要的概念:subvolumes和snapshots,Btrfs利用subvolumes和snapshots管理Docker镜像和Docker容器的分层。

Subvolumes是指Btrfs文件系统的一部安排置,或者也可称为Btrfs文件系统的子文件系统,借助subvlolumes我们可以将一个大的文件系统划分成若干个子文件系统,这些子文件系统共享底层的设备空间,在需要磁盘空间时便从底层设备中进行猎取,整个过程类似malloc()安排内存空间的过程。我们在使用Btrfs文件系统时,通常为了比较便利的使用设备的空间,Btrfs会将磁盘空间划分成多个块,需要留意的是划分的这些块的空间安排策略可以是不同的,比如,实际使用中我们可能会将一部分的块用来存储元数据,将另一部分的块用来存储我们实际的业务数据。

Snapshots是subvolumes的一个实时读写拷贝,其安排单位称为块,一般每个块的大小为1GB。

Btrfs文件系统将一个文件系统当成一个资源池来进行看待,这个资源池中会有多个子文件系统,我们可以动态的往资源池中进行子文件系统的添加。

2.Btrfs避坑

先看下Btrfs的优势和适合的业务场景。

相比我们常常使用的ext4文件系统,Btrfs文件系统在许多方面都做了改进,比如大家熟知的支持子卷、支持快照,除了这些功能,Btrfs文件系统还内置了压缩和RAID的支持等功能。

相比传统的文件系统,虽然Btrfs引入了许多特别棒的特性,但它存在的问题也同样的突出。

(1)Btrfs文件系统未引入页缓存共享的机制,这就导致Btrfs文件系统不适合在容器密度比较高的场景下进行使用。由于没有页缓存共享,多个容器在访问相同的文件时需要对文件缓存多次。

(2)Btrfs文件系统中使用的smallwrite功能导致整个文件系统存在性能瓶颈。

(3)Btrfs文件系统写数据的方式是journalin

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论