栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Go语言

【containerd 源码分析】containerd image list 源码分析

Go语言 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【containerd 源码分析】containerd image list 源码分析

    本文分析 containerd 列出所有镜像的分析过程,包括 ctr image 命令行以及 containerd daemon 执行 过程,也包含镜像 metadata,content 等内容。

1. 执行如下命令 ctr images list

    首先分析 ctr 命令,实现在 cmd/ctr 的子命令 listCommand 实现,利用 GRPC 链接到 remote cotainerd 端请求,使用了如下两个服务,其中 imageStore 实现了文件 image/images.go 的 Store 接口,cs 实现了 content/content.go Store 接口,如下 1.1 1.2 所示:

imageStore = client.ImageService()
cs         = client.ContentStore()
   1.1 文件 image/image.go 接口 Store

    Store 接口很好理解,增删改查的操作。

// Store and interact with images
type Store interface {
	Get(ctx context.Context, name string) (Image, error)
	List(ctx context.Context, filters ...string) ([]Image, error)
	Create(ctx context.Context, image Image) (Image, error)

	// Update will replace the data in the store with the provided image. If
	// one or more fieldpaths are provided, only those fields will be updated.
	Update(ctx context.Context, image Image, fieldpaths ...string) (Image, error)

	Delete(ctx context.Context, name string, opts ...DeleteOpt) error
}
   1.2 文件 content/content.go 接口 Store

    Store 接口包含四个匿名接口, Manager 提供了 content 接口, Provider 提供了指定内容的读接口, IngestManager 提供了管理 ingest 的方法, Ingester 提供了写 content 的方法。

// Store combines the methods of content-oriented interfaces into a set that
// are commonly provided by complete implementations.
type Store interface {
	Manager
	Provider
	IngestManager
	Ingester
}

2. 向 containerd 发起 list 请求 
imageList, err := imageStore.List(ctx, filters...)
   2.1 containerd 处理 GRPC ListImagesRequest 请求

    其核心处理函数在 containerd/services.images/service.go 文件中 List 方法。

func (c *imagesClient) List(ctx context.Context, in *ListImagesRequest, opts ...grpc.CallOption) (*ListImagesResponse, error) {
	out := new(ListImagesResponse)
	err := c.cc.Invoke(ctx, "/containerd.services.images.v1.Images/List", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}
    2.2 service List 方法

    看出最终调用的是 local.List 方法, 那主要分析到 local 实现也在相同目录 containerd/services.images 中。

func (s *service) List(ctx context.Context, req *imagesapi.ListImagesRequest) (*imagesapi.ListImagesResponse, error) {
	return s.local.List(ctx, req)
}
   2.3 结构体 local

   其中又包含三个接口, store gcScheduler Publisher, local 实现了 ImagesClient 的接口

type local struct {
	store     images.Store
	gc        gcScheduler
	publisher events.Publisher
}

var _ imagesapi.ImagesClient = &local{}
   2.4 初始化 init 注册插件 io.containerd.service.v1

    io.containerd.service.v1 需要插件 io.containerd.metadata.v1 和 io.containerd.gc.v1, 可以看出来 store 接口是插件 io.containerd.metadata.v1 实现的。 在看看 metadata 初始化插件

func init() {
	plugin.Register(&plugin.Registration{
		Type: plugin.ServicePlugin,
		ID:   services.ImagesService,
		Requires: []plugin.Type{
			plugin.MetadataPlugin,
			plugin.GCPlugin,
		},
		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
			m, err := ic.Get(plugin.MetadataPlugin)
			if err != nil {
				return nil, err
			}
			g, err := ic.Get(plugin.GCPlugin)
			if err != nil {
				return nil, err
			}

			return &local{
				store:     metadata.NewImageStore(m.(*metadata.DB)),
				publisher: ic.Events,
				gc:        g.(gcScheduler),
			}, nil
		},
	})
}
   2.5 插件 metadata 初始化

    可以看出来使用的 db 为 bolt, 在 io.containerd.metadata.v1.bolt 目录创建了数据库文件 meta.db。

	plugin.Register(&plugin.Registration{
		Type: plugin.MetadataPlugin,
		ID:   "bolt",
		Requires: []plugin.Type{
			plugin.ContentPlugin,
			plugin.SnapshotPlugin,
		},
		Config: &srvconfig.BoltConfig{
			ContentSharingPolicy: srvconfig.SharingPolicyShared,
		},
		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
            .........................
			db, err := bolt.Open(path, 0644, &options)
			close(doneCh)
			if err != nil {
				return nil, err
			}

			var dbopts []metadata.DBOpt
			if !shared {
				dbopts = append(dbopts, metadata.WithPolicyIsolated)
			}
			mdb := metadata.NewDB(db, cs.(content.Store), snapshotters, dbopts...)

    回到正题, 还是继续看 List 流程, 可以看到调用了 store.List 方法, 实现为 boltdb 数据库。

func (l *local) List(ctx context.Context, req *imagesapi.ListImagesRequest, _ ...grpc.CallOption) (*imagesapi.ListImagesResponse, error) {
	images, err := l.store.List(ctx, req.Filters...)
	if err != nil {
		return nil, errdefs.ToGRPC(err)
	}

	return &imagesapi.ListImagesResponse{
		Images: imagesToProto(images),
	}, nil
}

    这里以 namespace 作为 bucket, 剩下的就从 boltdb 读取, key value 读取完成,  具体内容在后续 pull 镜像讲解。

func (s *imageStore) List(ctx context.Context, fs ...string) ([]images.Image, error) {
	namespace, err := namespaces.NamespaceRequired(ctx)
	if err != nil {
		return nil, err
	}

总结:

   list image 依赖 metadata 数据库 boltdb 读取 key,value

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/990279.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号