![7473e9683a8c338d6a7c730a8adb23f5.png](https://i-blog.csdnimg.cn/blog_migrate/eab6ae8ff82bd0cac362f499fc18cf09.jpeg)
作者 | 阚俊宝 阿里云技术专家
导读:云原生存储详解系列文章将从云原生存储服务的概念、特点、需求、原理、使用及案例等方面,和大家一起探讨云原生存储技术新的机遇与挑战。本文为该系列文章的第二篇,会对容器存储的相关概念进行讲述,欢迎大家在留言区参与讨论。
云原生存储的两个关键领域:Docker 存储卷、K8s 存储卷;
- Docker 存储卷:容器服务在单节点的存储组织形式,关注数据存储、容器运行时的相关技术;
- K8s 存储卷:关注容器集群的存储编排,从应用使用存储的角度关注存储服务。
Docker 存储
容器服务之所以如此流行,一大优势即来自于运行容器时容器镜像的组织形式。容器通过复用容器镜像的技术,实现在相同节点上多个容器共享一个镜像资源(更细一点说是共享某一个镜像层),避免了每次启动容器时都拷贝、加载镜像文件,这种方式既节省了主机的存储空间,又提高了容器启动效率。
1. 容器读写层
为了提高节点存储的使用效率,容器不光在不同运行的容器之间共享镜像资源,而且还实现了在不同镜像之间共享数据。共享镜像数据的实现原理:镜像是分层组合而成的,即一个完整的镜像会包含多个数据层,每层数据相互叠加、覆盖组成了最终的完整镜像。
为了实现多个容器间共享镜像数据,容器镜像每一层都是只读的。而通过实践我们得知,使用镜像启动一个容器的时候,其实是可以在容器里随意读写的,这是如何实现的呢?
容器使用镜像时,在多个镜像分层的最上面还添加了一个读写层。每一个容器在运行时,都会基于当前镜像在其最上层挂载一个读写层,用户针对容器的所有操作都在读写层中完成。一旦容器销毁,这个读写层也随之销毁。
![27991eb690ac82d680a18ebfe4081ec4.png](https://i-blog.csdnimg.cn/blog_migrate/0c5119a22abb3c0902cfe8e6f930fc8b.jpeg)
如上图所示例子,一个节点上共有 3 个容器,分别基于 2 个镜像运行。
镜像存储层说明如下:
该节点上共包含 6 个镜像层:Layer 1~6。
镜像 1 由:Layer 1、3、4、5 组成;镜像 2 由:Layer 2、3、5、6 组成。
所以两个镜像共享了 Layer 3、5 两个镜像层;
容器存储说明:
容器 1:使用镜像 1 启动容器 2:使用镜像 1 启动容器 3:使用镜像 2 启动
容器 1 和容器 2 共享镜像 1,且每个容器有自己的可写层;容器 1(2)和容器 3 共享镜像 2 个层(Layer3、5);
通过上述例子可以看到,通过容器镜像分层实现数据共享可以大幅减少容器服务对主机存储的资源需求。
上面给出了容器读写层结构,而读写的原则:
对于读:容器由这么多层的数据组合而成,当不同层次的数据重复时,读取的原则是上层数据覆盖下层数据;对于写:容器修改某个文件时,都是在最上层的读写层进行。主要实现技术有:写时复制、用时配置。
1)写时复制
写时复制(CoW:copy-on-write),表示只在需要写时才去复制,是针对已有文件的修改场景。CoW 技术可以让所有的容器共享 image 的文件系统,所有数据都从 image 中读取,只有当要对文件进行写操作时,才从 image 里把要写的文件复制到最上面的读写层进行修改。所以无论有多少个容器共享同一个 image,所做的写操作都是对从 image 中复制后在复本上进行,并不会修改 image 的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个复本,每个容器修改的都是自己的复本,相互隔离,相互不影响。
2)用时配置
用时分配:在镜像中原本没有某个文件的场景,只有在要新写入一个文件时才分配空间,这样可以提高存储资源的利用率。比如启动一个容器,并不会为这个容器预分配一些磁盘空间,而是当有新文件写入时,才按需分配新空间。
2. 存储驱动
存储驱动是指如何对容器的各层数据进行管理,已达到上述需要实现共享、可读写的效果。即:容器存储驱动实现了容器读写层数据的存储和管理。常见的存储驱动:
- AUFS
- OverlayFS
- Devicemapper
- Btrfs
- ZFS
以 AUFS 为例,我们来讲述一下存储驱动的工作原理:
![695e9266ed3c96285d2393a99d721c56.png](https://i-blog.csdnimg.cn/blog_migrate/d5598f5ce5b479fc5557a03f3dbcc4cb.jpeg)
AUFS 是一种联合文件系统(UFS),是文件级的存储驱动。
AUFS 是一个能透明叠加一个或多个现有文件系统的层状文件系统,把多层文件系统合并成单层表示。即:支持将不同目录挂载到同一个虚拟文件系统下的文件系统。可以一层一层地叠加修改文件,其底层都是只读的,只有最上层的文件系统是可写的。当需要修改一个文件时,AUFS 创建该文件的一个副本,使用 CoW 将文件从只读层复制到可写层进行修改,结果也保存在可写层。在 Docker 中,底下的只读层就是 image,可写层就是 Container 运行时。
其他各种存储驱动这里不再细讲,有兴趣的同学可以到网上查询资料。
3. Docker 数据卷介绍
容器中的应用读写数据都是发生在容器的读写层,镜像层+读写层映射为容器内部文件系统、负责容器内部存储的底层架构。当我们需要容器内部应用和外部存储进行交互时,需要一个类似于计算机 U 盘一样的外置存储,容器数据卷即提供了这样的功能。
另一方面:容器本身的存储数据都是临时存储,在容器销毁的时候数据会一起删除。而通过数据卷将外部存储挂载到容器文件系统,应用可以引用外部数据,也可以将自己产出的数据持久化到数据卷中,所以容器数据卷是容器进行数据持久化的实现方式。
容器存储组成:只读层(容器镜像) + 读写层 + 外置存储(数据卷)
容器数据卷从作用范围可以分为:单机数据卷 和 集群数据卷。单机数据卷即为容器服务在一个节点上的数据卷挂载能力,docker volume 是单机数据卷的代表实现;集群数据卷则关注的是集群级别的数据卷编排能力,K8s 数据卷则是集群数据卷的主要应用方式。
Docker Volume 是一个可供多个容器使用的目录,它绕过 UFS,包含以下特性:
- 数据卷可以在容器之间共享和重用;
- 相比通过存储驱动实现的可写层,数据卷读写是直接对外置存储进行读写,效率更高;
- 对