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

 

posted on 2017-03-31 22:49  arwen_spy  阅读(466)  评论(0编辑  收藏  举报

导航