zoukankan      html  css  js  c++  java
  • docker 源码分析 二(基于1.8.2版本),docker client与daemon交互

    (2) 那我们通过docker客户端发送一个命令,docker是怎样接收到并处理的呢,我们就举个例子来看一下,比如docker pull 命令;

    我们回到 docker/docker.go 中,在上一章中我们讲了docker daemon的启动,代码讲到了handleGlobalDaemonFlag()的位置。我们接着继续看:

    c := cli.New(clientCli, daemonCli)
    if err := c.Run(flag.Args()...); err != nil {
        if sterr, ok := err.(cli.StatusError); ok {
            if sterr.Status != "" {
                fmt.Fprintln(os.Stderr, sterr.Status)
                os.Exit(1)
            }
            os.Exit(sterr.StatusCode)
        }
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    cli 在cli/cli.go文件中,

    func New(handlers ...Handler) *Cli {

        // make the generic Cli object the first cli handler

        // in order to handle `docker help` appropriately

        cli := new(Cli)

        cli.handlers = append([]Handler{cli}, handlers...)

        return cli

    }

    这里的handler就是各种处理方法的结合;

    然后是c.Run()方法,Run方法是调用了command方法,实质就是通过反射机制在handlers中找到args中名称相同的命令来执行:

    func (cli *Cli) command(args ...string) (func(...string) error, error) {

        for _, c := range cli.handlers {

            if c == nil {

                continue

            }

            camelArgs := make([]string, len(args))

            for i, s := range args {

                if len(s) == 0 {

                    return nil, errors.New("empty command")

                }

                camelArgs[i] = strings.ToUpper(s[:1]) + strings.ToLower(s[1:])

            }

            methodName := "Cmd" + strings.Join(camelArgs, "")

            method := reflect.ValueOf(c).MethodByName(methodName)

            if method.IsValid() {

                // type assert

                if c, ok := c.(Initializer); ok {

                    if err := c.Initialize(); err != nil {

                        return nil, initErr{err}

                    }

                }

                return method.Interface().(func(...string) error), nil

            }

        }

        return nil, errors.New("command not found")

    }

    比如我们运行docker pull,实际去查找的命令就是CmdPull。

    pull命令的实现是在 api/client 下面,这个目录下还有其他命令,我们只举pull的例子来看:

    pull.go中最主要的一句话是

    _, _, err = cli.clientRequestAttemptLogin("POST", "/images/create?"+v.Encode(), nil, cli.out, repoInfo.Index, "pull")

    clientRequestAttemptLogin在同目录的utils.go目录下;

    POST 是方法, /images.create? 这个是url,回想起上一章我们在apiserver(api/server/server.go)中看到的, 这url对应的是 s.postImagesCreate

    postImagesCreate的定义在api/server/image.go 中;

    现在大致了解了docker的c/s架构和docker客户端怎样给docker daemon发命令;下一篇来分析一下docker daemon的启动过程,也就是daemon.NewDaemon(cli.Config, registryService)函数的实现过程;

    因为docker daemon的启动过程涉及很多操作,包括网络环境初始化,存储初始化等等,先了解一下daemon的总体启动过程,然后再分每一项各个击破;


  • 相关阅读:
    获取手机安装的所有包名adb shell pm list packages
    启动管理
    日志管理
    系统管理:进程管理、终止进程、工作管理、系统资源查看
    报数出局问题,类似约瑟夫环(链表写法)
    多项式的链式写法
    简易的C语言地铁购票系统
    68-js 前端实现标签值的切换
    67-foreach 取循环的次数
    66-mybatis 插入数据返回主键
  • 原文地址:https://www.cnblogs.com/yuhan-TB/p/4842178.html
Copyright © 2011-2022 走看看