• docker 源码分析daemon 消息处理2


    接上回,如果是V2版本的Puller,位于pull_v2.go文件

    func (p *v2Puller) Pull(ctx context.Context, ref reference.Named) (err error) {
        p.repo, p.confirmedV2, err = NewV2Repository(ctx, p.repoInfo, p.endpoint, p.config.MetaHeaders, p.config.AuthConfig, "pull")
    ...
    
        if err = p.pullV2Repository(ctx, ref); err != nil {
    ...
    }

     新建一个V2版本的仓库赋值给p.repo,调用pullV2Respository函数

    func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named) (err error) {
        var layersDownloaded bool
        if !reference.IsNameOnly(ref) {
            layersDownloaded, err = p.pullV2Tag(ctx, ref)
    ...
        } else {
    ...
            for _, tag := range tags {
                tagRef, err := reference.WithTag(ref, tag)
    ....
                pulledNew, err := p.pullV2Tag(ctx, tagRef)
    ...
            }
        }
    ...
    }

    有tag的话,遍历tag,每个tag调用pullV2Tag,没有的话直接调用pullV2Tag

    func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named) (tagUpdated bool, err error) {
    ....
        switch v := manifest.(type) {
        case *schema1.SignedManifest:
            if p.config.RequireSchema2 {
                return false, fmt.Errorf("invalid manifest: not schema2")
            }
            id, manifestDigest, err = p.pullSchema1(ctx, ref, v)
            if err != nil {
                return false, err
            }
        case *schema2.DeserializedManifest:
            id, manifestDigest, err = p.pullSchema2(ctx, ref, v)
            if err != nil {
                return false, err
            }
        case *manifestlist.DeserializedManifestList:
            id, manifestDigest, err = p.pullManifestList(ctx, ref, v)
            if err != nil {
                return false, err
            }
        default:
            return false, errors.New("unsupported manifest format")
        }
    
    ....
    }

    先是获取 manifest 属性,根据属性的类型做不同的处理。pullManifestList 最终调用 pullSchema1或者pullSchema2 ,这2个函数只是对于参数的处理方式不同,最终下载镜像都是调用同样的处理函数 

    rootFS, release :=p.config.DownloadManager.Download(ctx, *rootFS, descriptors, p.config.ProgressOutput)

    imageID := p.config.ImageStore.Put(configJSON)     //  ImageStore:       distribution.NewImageConfigStoreFromStore(daemon.imageStore),

    DownloadManager 根据config初始化函数就应该是daemon的DownloadManager,而daemon的DownloadManager是通过下面函数构建的d.downloadManager = xfer.NewLayerDownloadManager(d.layerStore, *config.MaxConcurrentDownloads),位于distribution/xfer/download.go 是一个分层下载的阻塞函数。

            if topDownload != nil {
                xferFunc = ldm.makeDownloadFunc(descriptor, "", topDownload)
                defer topDownload.Transfer.Release(watcher)
            } else {
                xferFunc = ldm.makeDownloadFunc(descriptor, rootFS.ChainID(), nil)
            }
            topDownloadUncasted, watcher = ldm.tm.Transfer(transferKey, xferFunc, progressOutput)

    download内调用makeDownloadFunc创建下载函数xferFunc,xferFunc函数内部初始化一个downloadTransfer 并返回。

    xferFunc内部创建一个协程处理progressChan通道,调用descriptor.Download(..) , 这个是pull_v2.go内部初始化的v2LayerDescriptor,返回 io.ReadCloser,

    再通过io.ReadCloser 创建 reader解压数据,利用downloadTransfer处理数据。

    Transfer函数位于/distribution/xfer/transfer.go,调用xferFunc创建 downloadTransfer并把通道信息传给xferFunc创建的协程,返回Transfer, Watcher

    Put是下面函数

    func (s *imageConfigStore) Put(c []byte) (digest.Digest, error) {
        id, err := s.Store.Create(c)
        return digest.Digest(id), err
    }

    调用 image/store.go 的Create函数把byte数据在本地创建image

  • 相关阅读:
    软件工程-案例分析作业 开源代码托管平台
    软件工程-个人阅读作业 #2
    软件工程-个人阅读作业 #1
    提问回顾与个人总结
    软工案例分析作业
    结对编程——第二阶段
    软工个人阅读作业#2
    软工个人阅读作业#1
    OO补给站总结
    BUAA_2021_SE_Final_Report
  • 原文地址:https://www.cnblogs.com/arwen-spy/p/6629299.html
Copyright © 2020-2023  润新知