docker 源码分析daemon 消息处理1

在 cmd/dockerd/daemon.go 文件 initRouter 函数中 初始化 router

    routers := []router.Router{
        checkpointrouter.NewRouter(d, decoder),
        container.NewRouter(d, decoder),
        image.NewRouter(d, decoder),
        systemrouter.NewRouter(d, c),
        volume.NewRouter(d),
        build.NewRouter(dockerfile.NewBuildManager(d)),
        swarmrouter.NewRouter(c),
        pluginrouter.NewRouter(d.PluginManager()),
    }

以pull命令为例, image的处理函数在 api/server/router/image 的image 包

image.go 新建路由 NewRouter 函数创建 imageRouter 实例并初始化路由

func (r *imageRouter) initRoutes() {
    r.routes = []router.Route{
        // GET
        router.NewGetRoute("/images/json", r.getImagesJSON),
        router.NewGetRoute("/images/search", r.getImagesSearch),
        router.NewGetRoute("/images/get", r.getImagesGet),
        router.NewGetRoute("/images/{name:.*}/get", r.getImagesGet),
        router.NewGetRoute("/images/{name:.*}/history", r.getImagesHistory),
        router.NewGetRoute("/images/{name:.*}/json", r.getImagesByName),
        // POST
        router.NewPostRoute("/commit", r.postCommit),
        router.NewPostRoute("/images/load", r.postImagesLoad),
        router.Cancellable(router.NewPostRoute("/images/create", r.postImagesCreate)),
        router.Cancellable(router.NewPostRoute("/images/{name:.*}/push", r.postImagesPush)),
        router.NewPostRoute("/images/{name:.*}/tag", r.postImagesTag),
        router.NewPostRoute("/images/prune", r.postImagesPrune),
        // DELETE
        router.NewDeleteRoute("/images/{name:.*}", r.deleteImages),
    }
}

pull命令对应的restful api是"/images/create", 会调用 imageRouter 的postImagesCreate 函数,函数位于image包的image_routes.go

func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
...
    if image != "" { //pull
....
        err = s.backend.PullImage(ctx, image, tag, metaHeaders, authConfig, output)
    } else { //import
...
        err = s.backend.ImportImage(src, repo, tag, message, r.Body, output, r.Form["changes"])
    }
...
}

函数解码之后对于pull命令调用imageRouter 的 backend.PullImage

image包中backend.go是一些接口,真正的backend是初始化时传入的daemon,因此调用的是 daemon/image_pull.go的 PullImage  函数

func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
    ...
    return daemon.pullImageWithReference(ctx, ref, metaHeaders, authConfig, outStream)
}

如果传入tag,则需要处理tag,然后调用pullImageWithReference 函数

func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
    progressChan := make(chan progress.Progress, 100)

    writesDone := make(chan struct{})

    ctx, cancelFunc := context.WithCancel(ctx)

    go func() {
        progressutils.WriteDistributionProgress(cancelFunc, outStream, progressChan)
        close(writesDone)
    }()

    imagePullConfig := &distribution.ImagePullConfig{
....
    }

    err := distribution.Pull(ctx, ref, imagePullConfig)
    close(progressChan)
    <-writesDone
    return err
}
progressChan 通道是用来显示pull操作的状态, writesDone 用来等待协程处理结束,创建config实例,调用 distribution/pull.go 内的Pull 函数
func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullConfig) error {
    repoInfo, err := imagePullConfig.RegistryService.ResolveRepository(ref)
    ...

    endpoints, err := imagePullConfig.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
    .....
    for _, endpoint := range endpoints {
    ...

        puller, err := newPuller(endpoint, repoInfo, imagePullConfig)
...
        if err := puller.Pull(ctx, ref); err != nil {
    .....
        }
...
    }
....
}

获取仓库端信息,遍历端点,根据api版本创建V1或V2版本的puller的Pull 函数,先分析到这里

posted on 2017-03-27 22:37  arwen_spy  阅读(374)  评论(0编辑  收藏  举报

导航