Docker存储技术浅析

Docker在Linux上支持很多存储驱动,每种驱动都有自己的镜像分层、镜像层共享以及写时复制(CoW)技术的具体实现。

Docker存储基础技术

镜像分层

所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。默认Docker镜像由多个只读层镜像叠加而成,启动容器后,Docker会加载只读镜像层,并再顶部添加一个读写层,并通过写时复制的方式,来写读写层

镜像层共享

多个镜像之间可以并且确实会共享镜像层,这样可以有效节省空间 并提升性能。例如多个centos7的镜像可以共享centos7的基础image,因为基础image大家都一样

写时复制CoW

CoW就是copy-on-write,表示只在需要写时才去复制,这个是针对已有文件的修改场景。比如基于一个image启动多个Container,如果为每个Container都去分配一个image一样的文件系统,那么将会占用大量的磁盘空间。而CoW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。所以无论有多少个容器共享同一个image,所做的写操作都是对从image中复制到自己的文件系统中的复本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个复本,每个容器修改的都是自己的复本,相互隔离,相互不影响。使用CoW可以有效的提高磁盘的利用率。

非持久性存储

每个Docker容器都有自己的非持久化存储,即容器的本地存储,默认情况这是容器全部文件和文件系统保存的地方。非持久化存储自动创建,从属于容器,生命周期与容器相同,这意味着删除容器也会删除全部非持久化数据。

持久性存储

在redhat和centos环境,官方主要支持使用如下几种存储驱动。性能最好的为overlay2,目前官方在redhat和centos环境,推荐使用overlay2。

devicemapper驱动

在linux2.6内核版本中并入内核,devicemapper将所有的镜像和容器存储在自己的虚拟块设备上,devicemapper工作在块层次上而不是文件层次上。在Docker 17.06以及更高的版本中可以配置direct-lvm 作为存储驱动,这种模式下通过使用基于裸块设备 (Raw Block Device)的LVM精简池(LVM thin pool)来获取更好的性能。

overlay驱动


如上图所示,Overlay在主机上用到2个目录,这2个目录被看成是overlay的层。upperdir为容器层、lowerdir为镜像层使用联合挂载技术将它们挂载在同一目录(merged)下,提供统一视图。

overlay只使用2层,意味着多层镜像不会被实现为多个OverlayFS层。每个镜像被实现为自己的目录,这个目录在路径/var/lib/docker/overlay下。硬链接被用来索引和低层共享的数据,节省了空间,但是会有inode占用过多的问题。

当创建一个容器时,overlay驱动连接代表镜像层顶层的目录(只读)和一个代表容器层的新目录(读写)。

overlay2驱动

docker的overlay2驱动需要在kernel 3.10.0-514以上和Docker 17.06以上版本支持。而centos/redhat7系统默认内核为3.10.*。overlay2可以直接造成muitiple lower layers(最大128层)不用像overlay一样要通过硬链接的方式共享数据。
在overlay2每层的内容都是不一样的,diff是文件系统的统一挂载点,link文件描述的是该层的标识符,lower文件描述了层与层之间的组织关系,overlay2是将底层多个lowerdir和upperdir和workdir联合挂载,形成最终的merged挂载点。

如下为ubuntu:18.04的镜像

/var/lib/docker/overlay2/
|-- 6e599f35a3366d95287390fc00183a80bfc9a34492aaf9694836ec7b5722d0b6
|   |-- diff
|   |-- link
|   |-- lower
|   |-- merged
|   `-- work
|-- 6f66846fe6a29834193bf36380eb1664947f21435edd8ce8fbc9b79dea92c51b
|   |-- diff
|   |-- link
|   |-- lower
|   |-- merged
|   `-- work
|-- a1869d02b056d66742372c4b6d31d64f98b477590cdd76a842a653424f46710b
|   |-- diff
|   |-- link
|   |-- lower
|   |-- merged
|   `-- work
|-- backingFsBlockDev
|-- da05539957d703ae81cf279c76059c947c96bd1f91fd24691b9e7630dcb13ff7
|   |-- diff
|   `-- link
`-- l
    |-- 2LYVTSJQWPVOB46BCA74GFHJ7T -> ../da05539957d703ae81cf279c76059c947c96bd1f91fd24691b9e7630dcb13ff7/diff
    |-- HEXAQW5O23XL6HHRVOMKWGAI4Z -> ../6f66846fe6a29834193bf36380eb1664947f21435edd8ce8fbc9b79dea92c51b/diff
    |-- KXIOHK4OI6PPPFZ56I3ZORNHS7 -> ../6e599f35a3366d95287390fc00183a80bfc9a34492aaf9694836ec7b5722d0b6/diff
    `-- PHQQ6RCEXR6BLZJGKBP6GYS55Q -> ../a1869d02b056d66742372c4b6d31d64f98b477590cdd76a842a653424f46710b/diff

overlay相比overlay2要更加占用inode

1、overlay只支持两层lowerdir和upperdir,并且只支持一个lowerdir,所以如果你的容器镜像有多层的话,层与层之前的数据共享是通过硬链接来实现的,我们也知道硬链接本身是同一个inode但不同的文件名而已,但为什么还是会大量消耗inode这里简单做的实验
我们在一台配置了storage-driver的机器上PULL ubuntu:18.04镜像

[[email protected] dir]# docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
32802c0cfa4d: Pull complete
da1315cffa03: Pull complete
fa83472a3562: Pull complete
f85999a86bef: Pull complete
Digest: sha256:48eb09a5c832172357f172593ce5e98e027814f758f6aeaef59a7fd658e50d49
Status: Downloaded newer image for ubuntu:18.04

整个镜像是一个四层镜像层组成的镜像,在/var/lib/docker/overlay/下每层对应一个目录,通过tree命令可以看见每个目录内只包含一个root文件夹

tree -L 2 /var/lib/docker/overlay/
/var/lib/docker/overlay/
|-- 0a9cd41c44a802a325bfc5bfdda757bced8eaf69a8d6004e5d6fcb730591ab31
|   `-- root
|-- 1f9c95c6642a98930a14d914ac9bcfe9535b5a604dc27851cd76266326c76ed7
|   `-- root
|-- 2d79f688e1bf505ef20100f7450ad7e5ea550500bd07a17b7b9b08513fc96988
|   `-- root
`-- e8b1fcddec600628a75964619da3d0de7310fcbd6350b0c07ddf038d71c25d8b
    `-- root
8 directories, 0 files

这个root目录内包含的是该层独有的文件和根lowdir共享的数据硬链接,这里看见共享的数据他们本身都是通过硬链接方式连接起来的。

[[email protected] overlay]# ls  -i /var/lib/docker/overlay/0a9cd41c44a802a325bfc5bfdda757bced8eaf69a8d6004e5d6fcb730591ab31/root/bin/ls
70832997 /var/lib/docker/overlay/0a9cd41c44a802a325bfc5bfdda757bced8eaf69a8d6004e5d6fcb730591ab31/root/bin/ls
[[email protected] overlay]# ls  -i /var/lib/docker/overlay/1f9c95c6642a98930a14d914ac9bcfe9535b5a604dc27851cd76266326c76ed7/root/bin/ls
70832997 /var/lib/docker/overlay/1f9c95c6642a98930a14d914ac9bcfe9535b5a604dc27851cd76266326c76ed7/root/bin/ls
[[email protected] overlay]# ls  -i /var/lib/docker/overlay/2d79f688e1bf505ef20100f7450ad7e5ea550500bd07a17b7b9b08513fc96988/root/bin/ls
70832997 /var/lib/docker/overlay/2d79f688e1bf505ef20100f7450ad7e5ea550500bd07a17b7b9b08513fc96988/root/bin/ls
[[email protected] overlay]# ls  -i /var/lib/docker/overlay/e8b1fcddec600628a75964619da3d0de7310fcbd6350b0c07ddf038d71c25d8b/root/bin/ls
70832997 /var/lib/docker/overlay/e8b1fcddec600628a75964619da3d0de7310fcbd6350b0c07ddf038d71c25d8b/root/bin/ls

但为什么overlay还是会占用大量inode呢?根本原因在于那些文件夹,每层的root目录内存放的都是完整的rootfs文件夹,但它们都是新建出来
的,它们inode都不一样,所以在overlay下一个容器镜像层数越多,占用的inode就越多

四,参考资料
https://docs.docker.com/storage/storagedriver/overlayfs-driver/
https://docs.docker.com/storage/storagedriver/select-storage-driver/#supported-backing-filesystems
https://www.bladewan.com/2018/01/25/docker_storage_driver/

原文地址:https://blog.51cto.com/leejia/2482526

时间: 2024-08-30 08:21:10

Docker存储技术浅析的相关文章

Swarm 如何存储数据?- 每天5分钟玩转 Docker 容器技术(103)

service 的容器副本会 scale up/down,会 failover,会在不同的主机上创建和销毁,这就引出一个问题,如果 service 有要管理的数据,那么这些数据应该如何存放呢? 选项一:打包在容器里. 显然不行.除非数据不会发生变化,否则,如何在多个副本直接保持同步呢? 选项二:数据放在 Docker 主机的本地目录中,通过 volume 映射到容器里. 位于同一个主机的副本倒是能够共享这个 volume,但不同主机中的副本如何同步呢? 选项三:利用 Docker 的 volum

Docker 的两类存储资源 - 每天5分钟玩转 Docker 容器技术(38)

我们从本章开始讨论 Docker 存储. Docker 为容器提供了两种存放数据的资源: 由 storage driver 管理的镜像层和容器层. Data Volume. 我们会详细讨论它们的原理和特性. storage driver 在前面镜像章节我们学习到 Docker 镜像的分层结构,简单回顾一下. 容器由最上面一个可写的容器层,以及若干只读的镜像层组成,容器的数据就存放在这些层中.这样的分层结构最大的特性是 Copy-on-Write: 新数据会直接存放在最上面的容器层. 修改现有数据

如何实现跨 Docker 主机存储?- 每天5分钟玩转 Docker 容器技术(73)

从业务数据的角度看,容器可以分为两类:无状态(stateless)容器和有状态(stateful)容器. 无状态是指容器在运行过程中不需要保存数据,每次访问的结果不依赖上一次访问,比如提供静态页面的 web 服务器. 有状态是指容器需要保存数据,而且数据会发生变化,访问的结果依赖之前请求的处理结果,最典型的就是数据库服务器. 简单来讲,状态(state)就是数据,如果容器需要处理并存储数据,它就是有状态的,反之则无状态. 对于有状态的容器,如何保存数据呢? 前面在 Docker 存储章节我们学习

Docker存储驱动之Device Mapper简介

Device Mapper是一个基于kernel的框架,它增强了很多Linux上的高级卷管理技术.Docker的devicemapper驱动在镜像和容器管理上,利用了该框架的超配和快照功能.为了区别,本文使用Device Mapper指驱动中的框架,而devicemapper指Docker的存储驱动. 注意:商业支持的Docker Engine(CS-Engine)建议在RHEL和CentOS上使用devicemapper存储驱动. AUFS之外的另一种选择 Docker最初运行在Ubuntu和

理解Docker(7):Docker 存储 - AUFS

(1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 (4)Docker 容器的隔离性 - 使用 cgroups 限制容器使用的资源 (5)Docker 网络 (6)若干企业生产环境中的容器网络方案 (7)Docker 存储 - AUFS Docker 存储可以分为分层文件系统和卷,本文将介绍 AUFS 分层文件系统. 1. 基础知识 1.1 Linux 的 rootfs 和 bootfs 一

zookeeper技术浅析

Zookeeper是hadoop的一个子项目,虽然源自hadoop,但是我发现zookeeper脱离hadoop的范畴开发分布式框架的运用越来越多.今天我想谈谈zookeeper,本文不谈如何使用zookeeper,而是zookeeper到底有哪些实际的运用,哪些类型的应用能发挥zookeeper的优势,最后谈谈zookeeper对分布式网站架构能产生怎样的作用. Zookeeper是针对大型分布式系统的高可靠的协调系统.由这个定义我们知道zookeeper是个协调系统,作用的对象是分布式系统.

Docker存储驱动之OverlayFS简介

简介 OverlayFS是一种和AUFS很类似的文件系统,与AUFS相比,OverlayFS有以下特性: 1) 更简单地设计: 2) 从3.18开始,就进入了Linux内核主线: 3) 可能更快一些. 因此,OverlayFS在Docker社区关注度提高很快,被很多人认为是AUFS的继承者.就像宣称的一样,OverlayFS还很年轻.所以,在生成环境使用它时,还是需要更加当心. Docker的overlay存储驱动利用了很多OverlayFS特性来构建和管理镜像与容器的磁盘结构. 自从Docke

Docker实践(3)—浅析device mapeper的thin provoision

thin provision是在 kernel3.2 中引入的.它主要有以下一些特点: (1)允许多个虚拟设备存储在相同的数据卷中,从而达到共享数据,节省空间的目的: (2)支持任意深度的快照.之前的实现的性能为O(n),新的实现通过一个单独的数据避免了性能随快照深度的增加而降低. (3)支持元数据存储到单独的设备上.这样就可以将元数据放到镜像设备或者更快的SSD上. 上面3个特性正是devicemapper支持docker存储镜像的关键特性. 使用lvm管理thin provisioning

一文搞懂各种 Docker 网络 - 每天5分钟玩转 Docker 容器技术(72)

前面各小节我们先后学习了 Docker Overaly,Macvaln,Flannel,Weave 和 Calico 跨主机网络方案.目前这个领域是百家争鸣,而且还有新的方案不断涌现. 本节将从不同维度比较各种网络方案,大家在选择的时候可以参考.CloudMan 的建议是:没有最好的,只有最适合的,明确自己的需求,通过 PoC 选型. Docker 起初只提供了简单的 single-host 网络,显然这不利于 Docker 构建容器集群并通过 scale-out 方式横向扩展到多个主机上. 在