Docker源码分析
上QQ阅读APP看书,第一时间看更新

2.3.1 Docker Client解析请求命令

Docker Client解析请求命令的工作,在Docker命令执行部分第一个完成。创建Docker Client之后,回到main函数中,继续执行的源码如下(位于./docker/docker/docker.go#L102-L110):

if err := cli.Cmd(flag.Args()...); err != nil {
     if sterr, ok := err.(*utils.StatusError); ok {
          if sterr.Status != "" {
               log.Println(sterr.Status)
          }
          os.Exit(sterr.StatusCode)
     }
     log.Fatal(err)
}

学习以上源码可以发现,正如之前所说,Docker Client首先解析存放于flag.Args()中的具体请求参数,执行的函数为cli对象的Cmd函数。Cmd函数的定义如下(位于./docker/api/client/cli.go#L51-L61):

// Cmd executes the specified command
func (cli *DockerCli) Cmd(args ...string) error {
     if len(args) > 0 {
          method, exists := cli.getMethod(args[0])
          if !exists {
               fmt.Println("Error: Command not found:", args[0])
               return cli.CmdHelp(args[1:]...)
          }
          return method(args[1:]...)
     }
     return cli.CmdHelp(args...)
}

由代码注释可知,Cmd函数执行具体的指令。在源码实现中,首先判断请求参数列表的长度是否大于0。若长度不大于0,则说明没有请求信息,返回docker命令的Help信息;若长度大于1,则说明有请求信息,那么Docker Client首先通过请求参数列表中的第一个元素args[0]来获取具体的请求方法method。若上述method方法不存在,则返回docker命令的Help信息,若存在,调用具体的method方法,参数为args[1]及其之后所有的请求参数。

还是以一个具体的docker命令为例,docker--daemon=false--version=false pull Image_Name。通过以上Docker Client的分析,可以总结出以下执行流程。

1)解析flag参数之后,Docker将docker请求参数"pull"和"Image_Name"存放于flag.Args()。

2)创建好的Docker Client为cli,cli执行cli.Cmd(flag.Args()…)。

3)Cmd函数中,通过args[0]也就是"pull",执行cli.getMethod(args[0]),获取method的名称。

4)在getMothod方法中,Docker通过处理最终返回method值为"CmdPull"。

5)最终执行method(args[1:]…)也就是CmdPull(args[1:]…)。