• 11. [containerd] content服务解析


    containerd的核心Layer层存储组件content,用于存储下载的layer层数据,大家知道镜像是分层架构,一个镜像可能有很多Layer层组成,通过各Layer堆叠形成最终的文件系统,供运行时组件调用。本节详细分析content组件。

    一、content服务接口
    type Store interface {
    	Manager
    	Provider
    	IngestManager
    	Ingester
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.Manager用于Layer层数据的删改查,对应下面四个方法。Walk方法,是查询的一种,将过滤出来的content应用WalkFunc方法。最后一个查Info,并不是读取Layer层数据,而是获取其属性信息,包括文件大小、修改时间等。

    Delete(ctx context.Context, dgst digest.Digest) error
    Update(ctx context.Context, info Info, fieldpaths ...string) (Info, error)
    Walk(ctx context.Context, fn WalkFunc, filters ...string) error
    Info(ctx context.Context, dgst digest.Digest) (Info, error)	
    
    • 1
    • 2
    • 3
    • 4

    2.Provider用户Layer层数据的查询。下面方法读取数据。

    ReaderAt(ctx context.Context, desc ocispec.Descriptor) (ReaderAt, error)
    
    • 1

    3.IngestManager用于管理正在下载的Layer层数据,提供状态查询、中断等方法,上面两个方法是下载完成的Layer管理接口。

    Status(ctx context.Context, ref string) (Status, error)
    ListStatuses(ctx context.Context, filters ...string) ([]Status, error)
    Abort(ctx context.Context, ref string) error
    
    • 1
    • 2
    • 3

    4.Ingester用于下载Layer层数据,提供数据存储服务。

    Writer(ctx context.Context, opts ...WriterOpt) (Writer, error)
    
    • 1

    二、content组件设计

    containerd以插件形式管理各个组件,content组件生效需要提供两个组件标识。

    plugin.GRPCPlugin 将 content组件注册为GRPC服务,对外提供服务接口,ctr、crictl等客户端可以访问该服务。
    plugin.ServicePlugin 将content组件注册为一个功能服务,提供Layer层存储服务。
    plugin.MetadataPlugin 该组件是所有组件的元数据管理中心,用于存储各组件的管理数据。
    plugin.ContentPlugin content组件的存储实现服务,真正实现存储逻辑的。

    他们几个的关系:
    1)客户端调用从GRPCPlugin组件访问Content服务,GRPCPlugin加载ServicePlugin并调用其提供的服务。
    2)ServicePlugin 调用MetadataPlugin,调用其提供的服务。
    3)MetadataPlugin 调用ContentPlugin,调用其提供的存储服务。

    containerd的源代码在这方面确实有点混乱,这几个组件很多方法名称相同,连IDE也无法正确分辨。

    三、ContentPlugin

    1. 存储目录定义

    定义存储结构,组件包含两类数据,一类是正在下载的临时目录,一类是下载完成、验证完成的Layer层真实存储目录。

    1)下载完成的Layer层存储目录:/var/lib/containerd/io.containerd.content.v1.content/blobs
    2)Layer层临时存储目录:/var/lib/containerd/io.containerd.content.v1.content/ingest

    2. Layer层存储服务
    2.1)获取Layer层下载的Writer句柄

    IngesterWriter(ctx context.Context, opts ...WriterOpt) (Writer, error) 实现。

    1)存储Layer层数据,传入该Layer层的唯一标识,以及根据Manifest获取的Desc信息,Desc信息包含期望下载的Digest。
    2)ingest目录其{namespace/id/ref}文件夹下,定义两个子文件 ref文件、data文件,ref文件存储Layer层的唯一标识,data文件Layer层数据。
    3) 根据data文件是否有内容,判断是重新写入还是接着上次的offset继续写入。将data文件的WriteIO句柄封装到返回值Writer服务中。

    2.2)Writer服务

    1)Writer数据写入服务,这个好理解,写入Layer层数据到data文件
    2)Digest获取写入数据的Hash值
    3)Status获取已经写入数据状态,包括写入Size、Offset,以及期望的Digest等。
    4)Truncate文件内容清空,Reset文件的Offset等。
    5)Commit通知文件写入完毕,可以进行后续处理,例如将ingest文件存储到blobs目录。

    四、MetadataPlugin

    客户端真正的访问顺序,从MetadataPluginContentPlugin,在调用ContentPlugin存储Layer数据前,需要MetadataPlugin 先行对元数据进行处理。

    1. 存储

    metadata存储数据库:bolt
    metadata存储目录:/var/lib/containerd/io.containerd.metadata.v1.bolt

    2. 常用的存储字段

    1)该Layer层存储完毕,记录元数据

    Key:v1/{namespace}/content/blob/{digest}
    Key1: createdat
    Key2:updatedat
    Key3:size

    2)content的lease信息,下载完成后设置

    Key: v1/{namespace}/leases/{leaseID}/content/{Digest}
    Value: nil

    3)正在下载的ref记录

    Key:v1/{namespace}/content/ingests/{ref}
    Key1:ref Value:{namespace}/{boltID}{ref}
    Key2:expireat Value:{deadline time}
    Key3:expected Value:{Digest}

    4)下载环节设置,GC使用

    Key: v1/{namespace}/leases/{leaseID}/ingests/{ref}
    Value: nil

    五、GarbageCollect 垃圾回收

    content垃圾回收用于删除无用的content。

    遍历所有的content存储,在v1/{namespace}/content/blob/v1/{namespace}/content/ingests存在的content保留,其他删除。

  • 相关阅读:
    灵途科技荣获省级“专精特新”企业认定!
    【JavaEE---复习】四、事务
    leetcode 116. 填充每个节点的下一个右侧节点指针-java实现
    深度学习中的图像增强合集
    卷积神经网络结构设计,卷积神经网络最新进展
    Day19:属性封装详解
    Mysql、Oracle、Sql Service的区别
    关于一次两段式提交和数据库恢复数据我的一些想法
    搞创新,我们“REAL”在行!
    java手写最小栈算法和最小栈算法应用拓展案例
  • 原文地址:https://blog.csdn.net/xjmtxwd24/article/details/128142530