Docker容器数据持久化

容器中的数据可以存储在容器层。但是将数据存放在容器层存在以下问题:

  • 数据不是持久化。意思是如果容器删除了,这些数据也就没了
  • 主机上的其它进程不方便访问这些数据
  • 对这些数据的I/O会经过存储驱动,然后到达主机,引入了一层间接层,因此性能会有所下降

Docker提供了3种持久化数据的方式:

  1. volumes:存于主机文件系统中的某个区域,由Docker管理(/var/lib/docker/volumes/ on linux)。非Docker进程不应该修改这些数据。卷是Docker中持久化数据的最好方式
  2. bind mount:存于主机文件系统中的任意位置。非Docker进程可以修改这些数据
  3. tmpfs mount(Linux中):存于内存中(注意,并不是持久化到磁盘)。在容器的生命周期中,它能被容器用来存放非持久化的状态或敏感信息

使用FXMARK测试文件系统的多核可扩展性

并行I/O技术是一项用于提升应用性能的技术。随着NVMe设备的出现与发展,并发I/O能力增强。同时,CPU核数呈现增长的趋势。这使得很多高性能数据库开始利用多核来加速核心操作。但是,由于文件系统中存在诸如锁竞争、引用计数、cache-line竞争等扩展性瓶颈,因此文件系统操作的处理能力并不能随着核数的增加呈现出线性增长的关系。FxMark就是 USENIX Annual Technical Conference(ATC’16) 中文章 “Understanding Manycore Scalability of File Systems” 的作者开源的一套microbench套件,可以测试文件系统创建、删除、读/写等操作的多核扩展性

这篇博文从源码的角度分析FxMark的使用

Docker源码分析—镜像存储

基于Docker 17.05.x

Docker使用层存储来管理容器和镜像的层,那么如何知道哪些层属于某一个镜像?也就说如果现在系统上有很多个镜像,每个镜像又包括很多层,如果使用Overlay2,你可以在存储驱动目录下看到一大堆目录,如何知道哪些层是属于某个镜像?也就是说一个镜像如何和镜像层之间建立起关系

这篇文章主要通过分析Docker源码,介绍镜像存储的创建过程

Docker源码分析—层存储

基于Docker 17.05.x

Docker镜像由多层只读镜像层组成,Docker容器实际上就是创建了一层读写层,然后将这层读写层与使用的镜像关联起来。所以实际上镜像和容器在Docker中都是通过“层”来进行存储,每一层对应一个目录,Docker层存储就是用来管理这些“层”以及这些层的元数据

这篇文章根据Docker源码介绍Docker层存储的创建过程

C函数栈帧

一个可执行C程序由一系列二进制码组成,程序代码会被翻译成由二进制组成的机器指令。程序执行时,CPU取出程序指令执行,寄存器用于程序中变量数据的交换以及算术运算。由于寄存器数量等因素,程序执行过程中产生的数据(如变量)不会一直保存在寄存器中,变量和寄存器状态等会被保存在为函数分配的一个栈空间中,这个为函数分配的内存空间,就称为栈帧

栈帧可以加深对C中函数调用与返回的理解,了解函数的栈帧也有利于对C中一些问题进行更深入的思考:

  • 函数参数的传递过程
  • 局部变量的生命周期
  • 为什么应该将一些经常调用到的简短的函数定义为内敛函数

这篇文章使用VC++ 6.0对一个错误的swap函数进行调试,分析其栈帧结构,并解释错误的原因

内核OverlayFS—文件读写

内核版本4.4.68

文件(一般文件或目录)的读写和文件的创建删除不同,文件的创建删除作用于inode结构,需要用到inode操作。而文件的读写则是作用于file结构,因此需要用到file操作

通常,读写文件之前需要先打开这个文件,通过open系统调用,传入表示文件的路径字符串,随后内核会根据路径字符串进行路径查找,最终得到一个表示文件的file结构,并使之与当前进程相关联,之后的读写便会根据这个file结构来进行,这个结构的f_op字段是一个file操作的指针,file操作包含了文件读写函数的指针。OverlayFS中文件的读写也不例外,但是在OverlayFS中,一般文件的读写和目录的读写又有区别:

  • 一般文件的读写:在OverlayFS中,文件来源于upper层或lower层。在打开文件时,OverlayFS实际上打开的是upper层或者lower层的文件,因此随后发生的读写也就是对upper层或lower层的文件。
  • 目录的读写:与一般文件不同的是,目录的读写相对复杂。因为对于一个同时存在upper层和lower层的目录,在对该目录进行搜索时,OverlayFS会对upper层和lower层的目录分别进行搜索,然后做一些合并处理。但是对于同时存在于upper层或lower层的文件来说,由于”上层覆盖下层“,因此只需要读取upper层中文件就行了

正因如此,对于目录的读取,OverlayFS定义了自己的file操作,而对于一般文件的读写,OverlayFS不需要定义自己的操作

这篇文章重点在分析文件读写如何获得自己的读写操作,而不会深入的某个具体的读写函数。比如目录搜索是一个目录读写的例子,这部分另一篇博文有介绍,这里主要是分析OverlayFS中文件读写的本质

内核OverlayFS—创建与删除文件

内核版本4.4.68

在OverlayFS中,创建和删除一个文件实际上并不是在OverlayFS的联合挂载目录下进行,而是在upper目录进行

举个例子,如果OverlayFS中存在/dir目录,而且这个目录是一个upper目录,那么执行命令touch /dir/file实际上会在upper目录下的dir目录中创建一个file文件。如果/dir目录下存在file文件,想要删除这个文件,也是到upper目录下的dir目录中删除这个file文件

由于upper目录并不属于OverlayFS,假设upper目录是ext4下的一个目录,因此OverlayFS无法直接在upper目录下创建或删除文件。那么OverlayFS是如何实现upper目录下的文件创建与删除的?实际上,在OverlayFS定义的文件创建与删除的函数中,只是负责找到对应的upper层中的目录,然后将操作的控制权转交给VFS,然后VFS进一步调用upper目录实际文件系统定义的文件创建与删除函数。这篇文章就是通过两个实际例子来分析这些步骤是如何完成的

|