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

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

1. 执行如下命令 ctr image pull

    首先分析 ctr 命令,实现在 cmd/ctr 的子命令 listCommand 实现,利用 GRPC 链接到 remote cotainerd 端请求,核心函数 img, err := c.fetch(ctx, fetchCtx, ref, 0)

1.1 fetch 函数

    Resolver.Resolve 向 docker registry 请求 mainifest 文件清单, 本文示例镜像 docker.io/library/nginx:latest, 具体实现就不详细讲解, remotes/docker/resolver.go 中 dockerResolver 结构体实现了 Resolver 接口。

func (c *Client) fetch(ctx context.Context, rCtx *RemoteContext, ref string, limit int) (images.Image, error) {
	store := c.ContentStore()
	name, desc, err := rCtx.Resolver.Resolve(ctx, ref)

   name: 为 docker.io/library/nginx:latest;

   desc 为如下内容, Digest 在 response 的 header 里返回的;

   1.2 dockerResolver 实现 Fetcher 方法

    将镜像进行分析,包括远端 registry 名称, 仓库名称, tag等, 发请求就知道 host 地址

func (r *dockerResolver) Fetcher(ctx context.Context, ref string) (remotes.Fetcher, error) {
	base, err := r.resolveDockerBase(ref)
	if err != nil {
		return nil, err
	}

	return dockerFetcher{
		dockerBase: base,
	}, nil
}

   1.3 Dispatch 核心函数

   参数 handler 切片包含多个 handler 函数, descs 镜像的文件清单, 递归把子文件清单也处理了。 接着看几个关键的 handler 函数。

func Dispatch(ctx context.Context, handler Handler, limiter *semaphore.Weighted, descs ...ocispec.Descriptor) error {
	eg, ctx2 := errgroup.WithContext(ctx)
	for _, desc := range descs {
		desc := desc

		eg.Go(func() error {
			desc := desc

			children, err := handler.Handle(ctx2, desc)

			if len(children) > 0 {
				return Dispatch(ctx2, handler, limiter, children...)
			}

			return nil
		})
	}

	return eg.Wait()
}
		handlers := append(rCtx.BaseHandlers,
			remotes.FetchHandler(store, fetcher),
			convertibleHandler,
			childrenHandler,
			appendDistSrcLabelHandler,
		)

2. remotes FetchHandler 

   这里 ingester 是 store 接口, 实现的是 proxyContentStore 结构体, 路径为 content/proxy/content_store.go 文件, 其向 containerd 守护进程发起 GRPC 请求。 接着看 fetch 函数实现。

// FetchHandler returns a handler that will fetch all content into the ingester
// discovered in a call to Dispatch. Use with ChildrenHandler to do a full
// recursive fetch.
func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc {
	return func(ctx context.Context, desc ocispec.Descriptor) (subdescs []ocispec.Descriptor, err error) {
		switch desc.MediaType {
		default:
			err := fetch(ctx, ingester, fetcher, desc)
			return nil, err
		}
	}
}

   2.1 fetch 函数

    content.OpenWriter 向 containerd 发送 GRPC WriteContentRequest 请求, 包括 ref, total, digest。在看 containerd 处理 WriteContentRequest 请求。 containerd 先写入到 io.containerd.content.v1.content/ingest 下, 最后 commit GRPC WriteContentRequest 请求成功时在移入到 io.containerd.content.v1.content/blobs/sha256 目录下。

    fetcher.Fetch 实现在 remotes/docker/fetcher.go

func fetch(ctx context.Context, ingester content.Ingester, fetcher Fetcher, desc ocispec.Descriptor) error {
	cw, err := content.OpenWriter(ctx, ingester, content.WithRef(MakeRefKey(ctx, desc)), content.WithDescriptor(desc))

	ws, err := cw.Status()

	rc, err := fetcher.Fetch(ctx, desc)

	return content.Copy(ctx, cw, rc, desc.Size, desc.Digest)
}

总结:

    拉取镜像, 首先获取到 mainifest 文件清单, 在递归将子层下载到 content中, 最后将每一层解压到 snapshotter 下。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值