【探索docker存储之路】二、convoy背后干了啥?

前言

convoy作为一个docker volume plugin,支持不同的后端存储,为docker提供MountPoint,也就是一个的目录,可能是挂载了后端存储、本地块设备或者就是本地目录。
convoy的代码从结构、风格和使用的库,都与docker十分相似,并且比docker简单很多。在源码级别上值得留意的点,我感觉有两点。①插件式结构与interface的运用。② 作者对事物的抽象能力与方法。因为convoy版本目前只到0.4.3,其源代码还算成熟,是一份非常好的学习资料。
分析的源码版本基于docker1.10, convoy0.4.3

convoy client (convoy/client) 下图中蓝色部分

client模块主要服务于convoy的命令行,根据输入的命令行,执行不同的流程,除了daemon命令之外都是,最终通过自定义的http body的协议与convoy daemon进行通信。daemon命令时启动本地的convoy daemon,放到下一节详细说明。其他部分较简单,图中已详细表达,不再赘述。
【探索docker存储之路】二、convoy背后干了啥?_第1张图片

convoy daemon (convoy/daemon) 上图中黑色部分

daemon是主要的功能模块,可以接收来自convoy client和docker的命令,对backend存储进行了抽象,以便统一管理。下面先从daemon的启动开始。

daemon进程启动

  • 执行命令: convoy daemon –drivers glusterfs –driver-opts glusterfs.servers=192.168.0.3 –driver-opts glusterfs.defaultvolumepool=vol2
  • convoy程序解析参数,获得daemon子命令,调用到daemon.Start函数(convoy/daemon/daemon.go),Start函数中主要围绕daemon struct建立所需要环境和配置。
type daemon struct {
    Router              *mux.Router                          //http router
    ConvoyDrivers       map[string]convoydriver.ConvoyDriver //Drivers are compatible with backend storage
    GlobalLock          *sync.RWMutex
    NameUUIDIndex       *util.Index            //map[string]string with lock
    SnapshotVolumeIndex *util.Index            //map[string]string with lock
    UUIDIndex           *truncindex.TruncIndex //allows the retrieval of string identifiers by any of their unique prefixes  convoy 0.4.4 delete
    daemonConfig                               //config information
}
  • Driver初始化,优先从配置文件读取信息忽略命令行输入的参数,如果配置文件不存在则根据命令行参数初始化。
    convoy配置文件内容
    遍历DriverList,找到配置文件或命令行指定的Driver,执行初始化函数Init,并添加到daemon.ConvoyDrivers中。

  • 根据convoy的工作目录的内容,更新管理元数据,图1中也有相应的模块。

    • NameUUIDIndex: volume name : volume UUID
    • SnapshotVolumeIndex : snapshot UUID : volume UUID
    • UUIDIndex : volume UUID convoy 0.4.4 delete

【探索docker存储之路】二、convoy背后干了啥?_第2张图片

  • Router注册:Router提供两部分的路由,并将daemon的Router指向该Router。
    ① 处理convoy client的命令Client Request Router,处理客户端发送的http request。
    【探索docker存储之路】二、convoy背后干了啥?_第3张图片
    ②处理来自docker的请求Docker Volume Plugin Router,convoy本身就是docker的volume plugin,提供了如下的接口。
    【探索docker存储之路】二、convoy背后干了啥?_第4张图片

  • http server启动,根据sockFile=/var/run/convoy/convoy.sock 和 上一步骤的Router,启动http server。

daemon的请求处理逻辑

daemon启动后便可以处理请求(convoy client或docker),主要处理逻辑Router收到HTTP请求,将请求分发给各个模块:docker、volume、snapshot、backup。这个4个逻辑模块根据driver name(指定的或者默认的)从daemon.ConvoyDrivers中获取对应的Driver。ConvoyDrivers中的Driver是实现了ConvoyDriver interface的结构。
【探索docker存储之路】二、convoy背后干了啥?_第5张图片
从图4中可以看出ConvoyDriver接口规定了3组接口对应volume,snapshot,backup的操作,用于操作backend storage。逻辑处理最终调用这些接口访问Backend Storage。

ConvoyDriver implement

截止到0.4.3版本,convoy支持4中后端存储(实现了ConvoyDriver接口),如下表。
【探索docker存储之路】二、convoy背后干了啥?_第6张图片

下面来说说,convoy是如何对后端存储进行抽象和管理的,主要使用了4种结构Driver,Volume,Snapshot,Device。
* Driver:主要实现了ConvoyDriver接口,提供对Volume,Snapshot,Backup等功能。
* Volume:管理提供到docker或者convoy client的Volume。
* Snapshot:用于管理Volume的快照。
* Device:管理后端存储提供的存储空间,如:devicemapper的device;glusterfs的volume;vfs的目录等。
【探索docker存储之路】二、convoy背后干了啥?_第7张图片
上图Device结构内容,记录了该Driver的后端存储的信息。
【探索docker存储之路】二、convoy背后干了啥?_第8张图片

objectstore提供实现备份的框架

objectstore模块是实现BackupOperations接口所需要的基本功能,目前实现了两种备份后端:S3和VFS。提供了两种备份方案:DeltaBlockBackup(增量块)和BackupFile(备份文件)。
* devicemapper使用DeltaBlockBackup方式备份,实现了DeltaBlockBackupOperations接口。
* vfs使用BackFile方式备份。
* Volume,Snapshot,Backup用于管理备份存储的数据。
* ObjectStoreDriver后端备份存储需要实现的接口。
* S3ObjectStoreDriver,VfsObjectStoreDriver实现ObjectStoreDriver。

ebs在实现BackupOperations接口时,使用ebs自身的client来实现Backup。ebs本身就是一个分布式存储系统,不再需要额外的objectstore对其进行备份。
【探索docker存储之路】二、convoy背后干了啥?_第9张图片

通过vfs备份的目录结构:
【探索docker存储之路】二、convoy背后干了啥?_第10张图片

volume.cfg的内容,保存图6中的Volume结构
这里写图片描述

backup_[id].cfg,保存图6中的Backup结构
这里写图片描述
【探索docker存储之路】二、convoy背后干了啥?_第11张图片

blocks目录保存了snapshot存储的真实数据,以block的形式存储在不同目录。
【探索docker存储之路】二、convoy背后干了啥?_第12张图片

Convoy插件实现Docker API接口

  • Plugin.Activate : docker daemon和convoy daemon握手,规定返回Plugin的类型,volume plugin的类型为[“VolumeDriver”], convoy daemon收到这个请求也返回该字符串列表。
  • VolumeDriver.Create : 创建卷请求,convoy daemon收到请求后,调用后端存储,创建volume并将volume挂载到主机的一个目录上,返回这个目录的路径给docker。
  • VolumeDriver.Path : 卷创建成功后,docker可以通过Path请求获取指定卷的挂载路径。
  • VolumeDriver.Mount : 挂载后端卷到主机,convoy daemon将调用VolumeOperations.MountVolume函数,完成Mount操作,最终返回该volume的挂载路径给docker。
  • VolumeDriver.Unmount : 从主机卸载后端卷,容器退出时将触发,convoy daemon将调用VolumeOperations的UmountVolume函数。
  • VolumeDriver.Remove : 删除后端卷,删除容器时指定删除容器关联的卷时触发,convoy daemon将调用 VolumeOperations的DeleteVolume函数。

附convoy完整框架图:
【探索docker存储之路】二、convoy背后干了啥?_第13张图片

你可能感兴趣的:(docker,存储)