• 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的总体启动过程,然后再分每一项各个击破;


  • 相关阅读:
    CSS常用原子类base.css
    前端开发规范集锦
    C#(.NET) HMAC SHA256实现
    windows200364位iis6 php环境搭建
    MSSQL数据库分页存储过程
    C#动态调用webservice
    SQL语句之备份表
    双网卡内外网同时使用的方法
    SQL2008 提示评估期已过的解决方法
    时间服务器设置局域网时间同步
  • 原文地址:https://www.cnblogs.com/yuhan-TB/p/4842178.html
Copyright © 2020-2023  润新知