docker存储驱动
- docker可写层技术
- 写时复制
- 用时分配
- 驱动类型
- 1.AUFS
- 2.overlay
- 3.Device Mapper
- 4.btrfs
- 5.ZFS
- 存储驱动方式的对比
Docker 采用了C/S架构,包括客户端和服务端。Docker daemon作为服务端接受来自客户的请求,并处理这些请求(创建、运行、提交容器)。 客户端和服务端在一个机器上,通过RESTful API 来进行通信。具体到使用的过程中,就是在执行 service docker start 后,在主机(host)上产生docker deamon守护进程,在后台运行并等待接收来自客户端的消息
docker可写层技术
因为docker是采用的分层结构,下拉容器的时候,可以看到是一层一层的拉取容器镜像的,很显然这与镜像的分层特性有关。而每个容器运行的时候,都会为其分配一个可写层,容器所有的操作都是在读写层完成的,容器一旦销毁,为该容器分配的读写层也随之销毁
一个image可以启动多个容器,通过同一个Image启动的容器,全部都共享这个image。因为考虑到所有容器共享同一个image,会造成一个容器的改动对所有的容器都有影响的情况,因此在运行容器的时候会为每个容器都分配一个可写层,不同容器的可写层是互不影响的,所以容器也可以看成是镜像+可写层
而我们针对这个读写层的操作,主要基于两种方式:写时复制和用时分配
写时复制
写时复制是用在原本有该文件的场景
所有驱动都用到的技术——写时复制(CoW)。CoW就是copy-on-write,只在需要写时才去复制。比如基于一个image启动多个Container,如果为每个Container都去分配一个image一样的文件系统,那么将会占用大量的磁盘空间。而CoW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。所以无论有多少个容器共享同一个image,所做的写操作都是对从image中复制到自己的文件系统中的复本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个复本,每个容器修改的都是自己的复本,相互隔离,相互不影响。使用CoW可以有效的提高磁盘的利用率。
用时分配
用时分配是用在原本没有这个文件的场景
只有在要新写入一个文件时才分配空间,这样可以提高存储资源的利用率。比如启动一个容器,并不会为这个容器预分配一些磁盘空间,而是当有新文件写入时,才按需分配新空间。
docker容器采用以上两种技术,从而能够大大地提升其空间利用率,这也是docker镜像包很小的原因。
驱动类型
1.AUFS
Docker最开始采用AUFS作为文件系统,也得益于AUFS分层的概念,实现了多个Container可以共享同一个image。只在Ubuntu或者Debian的内核上才可以启用
AUFS(AnotherUnionFS)是一种Union FS,是文件级的存储驱动
其支持将不同目录挂载到同一个虚拟文件系统下。这种文件系统可以一层一层地叠加修改文件。无论底下有多少层都是只读的,只有最上层的文件系统是可写的。当需要修改一个文件时,AUFS创建该文件的一个副本,使用CoW技术将文件从只读层复制到可写层进行修改,结果也保存在可写层。在Docker中,底下的只读层就是image,可写层就是Container。
AUFS唯一一个storage driver可以实现容器间共享可执行及可共享的运行库, 所以当你跑成千上百个拥有相同程序代码或者运行库时时候,AUFS是个相当不错的选择
2.overlay
Overlay是Linux内核3.18后支持的,overlay也是一种Union FS
Overlay只有两层:一个upper文件系统和一个lower文件系统,分别代表Docker的镜像层和容器层。当需要修改一个文件时,使用CoW将文件从只读的lower复制到可写的upper进行修改,结果也保存在upper层。在Docker中,底下的只读层就是image,可写层就是Container。
3.Device Mapper
Device mapper是Linux内核2.6.9后支持的,提供的一种从逻辑设备到物理设备的映射框架机制,在该机制下,用户可以很方便的根据自己的需要制定实现存储资源的管理策略。
Device mapper是块级存储,所有的操作都是直接对块进行操作,而不是文件。
Device mapper驱动会先在块设备上创建一个资源池,然后在资源池上创建一个带有文件系统的基本设备,所有镜像都是这个基本设备的快照,而容器则是镜像的快照。(快照可以理解成某一时刻某事物的状态和及其描述数据)
当要写入一个新文件时,在容器的镜像内为其分配新的块并写入数据,这个叫用时分配。当要修改已有文件时,再使用CoW为容器快照分配块空间,将要修改的数据复制到在容器快照中新的块里再进行修改。Device mapper driver 会创建一个100G的简单文件包含你的镜像和容器,每一个容器被限制在10G大小的卷内
4.btrfs
Btrfs被称为下一代写时复制文件系统,并入Linux内核,也是文件级存储
但可以像Device mapper一样直接操作底层设备。Btrfs把文件系统的一部分配置为一个完整的子文件系统,称之为subvolume 。那么采用 subvolume,一个大的文件系统可以被划分为多个子文件系统,这些子文件系统共享底层的设备空间,在需要磁盘空间时便从底层设备中分配,类似应用程序调用 malloc()分配内存一样。为了灵活利用设备空间,Btrfs 将磁盘空间划分为多个chunk 。每个chunk可以使用不同的磁盘空间分配策略。比如某些chunk只存放metadata,某些chunk只存放数据。
Btrfs把一个大的文件系统当成一个资源池,配置成多个完整的子文件系统,还可以往资源池里加新的子文件系统,而基础镜像则是子文件系统的快照,每个子镜像和容器都有自己的快照,这些快照则都是subvolume的快照。
当写入一个新文件时,会在容器的快照里为其分配一个新的数据块,文件写在这个空间里,这个叫用时分配。而当要修改已有文件时,使用CoW复制分配一个新的原始数据和快照,在这个新分配的空间变更数据,变结束再更新相关的数据结构指向新子文件系统和快照,原来的原始数据和快照没有指针指向,被覆盖。
Btrfs 支持创建快照(snapshot)和克隆(clone),还能够方便的管理多个物理设备
5.ZFS
ZFS 文件系统是一个革命性的全新的文件系统,它从根本上改变了文件系统的管理方式,ZFS 完全抛弃了“卷管理”,不再创建虚拟的卷,而是把所有设备集中到一个存储池中来进行管理,用“存储池”的概念来管理物理存储空间。ZFS创建在虚拟的,被称为“zpools”的存储池之上。每个存储池由若干虚拟设备(virtual devices,vdevs)组成。这些虚拟设备可以是原始磁盘,也可能是一个RAID1镜像设备,或是非标准RAID等级的多磁盘组。于是zpool上的文件系统可以使用这些虚拟设备的总存储容量。
首先从zpool里分配一个ZFS文件系统给镜像的基础层,而其他镜像层则是这个ZFS文件系统快照的克隆,快照是只读的,而克隆是可写的,当容器启动时则在镜像的最顶层生成一个可写层。
当要写一个新文件时,使用按需分配,一个新的数据块从zpool里生成,新的数据写入这个块,而这个新空间存于容器(ZFS的克隆)里。当要修改一个已存在的文件时,使用写时复制,分配一个新空间并把原始数据复制到新空间完成修改。
zfs 是高密度工作负载(如PaaS)的理想选择
存储驱动方式的对比
1.块级存储适用于当文件特别大而修改的内容很小
存储驱动支持的文件系统类型如下:
文章内容参照文档: