docker 代码阅读记录 -- docker cli 组件

docker 代码阅读之路 -- docker cli 组件

    • docker cli 组件
    • 编译使用
    • Cobra 命令行库
    • cli 目录结构分析
    • docker.go main 入口函数与 DockerClient 类
    • cobra Command 与 docker build 示例
    • 参考

docker cli 组件

docker 在主要的组件有cli、server、register、image、container 等,其中 cli 便是 docker 的客户端的。它的源代码也即 docker/cli 目录下,主要用于解析用户通过 “docker” 命令行的操作。

编译使用

通过以下步骤可以单独编译 cli 组件。

  1. 首先下载 cli 源码,docker 相关的组件被整理到了 git clone https://github.com/docker/ 下,其中包括 cli 部分的源代码。

     cd $GOPATH/src/github.com/docker/cli/cmd/docker
     git clone https://github.com/docker/cli.git
    
  2. 进入 docker cli 组件的入口目录

     cd cli/cmd/docker
    
  3. 编译(需要 golang 环境,这里使用最新版本 golang 1.11 进行编译)

     go build .
    

    将在目录下生成 docker 二进制文件,可以直接运行。若本机已经安装过 docker 并启动了 server, 则可以用该二进制文件操作本机的 docker 服务。

  4. 使用编译出的命令行工具

     ./docker --help
    

Cobra 命令行库

如果直接看 cli 的代码,可能并不简单。这里首先了解下 Cobra 的使用,可以帮助更快了解 docker cli 的源码结构。
cobra 是 golang 语言中一个命令行库,用 cobra 可以快速的构建命令行及对应的执行函数。 kubernetes 、 etcd 、 docker 、OpenShift 等工具都用它构建命令行。
它的源代码在 https://github.com/spf13/cobra。
下面是用 cobra 构建一个命令行的例子。

  1. 安装 cobra

      go get -v github.com/spf13/cobra/cobra
    
  2. 使用 cobra 创建一个 demo

    cobra init demo
    
  3. 自动生成了代码,目录结构如下

     demo
     ▾ cmd/
             root.go
      main.go 
    
  4. 如下所示

cli 目录结构分析

接下来,看看 docker/cli 的目录结构,根目录下的文件、目录可以首先了解 cli 和 cmd 目录,其中 cmd 目录是入口代码的目录,熟悉 golang 的一定不陌生,而 cmd 便包含大量使用 cobra 库构建的子命令。

├── appveyor.yml
├── AUTHORS
├── circle.yml
├── cli
├── cmd
├── codecov.yml
├── contrib
├── CONTRIBUTING.md
├── dockerfiles
├── docker.Makefile
├── docs
├── e2e
├── experimental
├── gometalinter.json
├── internal
├── Jenkinsfile
├── kubernetes
├── LICENSE
├── MAINTAINERS
├── Makefile
├── man
├── NOTICE
├── opts
├── poule.yml
├── README.md
├── scripts
├── service
├── templates
├── TESTING.md
├── types
├── vendor
├── vendor.conf
└── VERSION

cmd 包含 docker cli 的入口文件 cmd/docker/docker.go 的目录。
而 cli 目录下包含了 cobra 创建的子命令,以及其对应的执行,子命令分为

[ image ] 镜像相关命令,包括 push 、create 、pull 等
[container] 容器相关命令,包括 run 、attach 、start、export、exec、logs 等
[secret、config] 操作 secret、config 的命令,用于支持 swarm
[system] 可以看到 docker 所用系统的一些信息,如磁盘占用等
[…] cli/cli/commands 目录下的子目录都代表一类命令。

docker.go main 入口函数与 DockerClient 类

docker cli 的入口在 cmd/docker/docker.go 中,主要是创建一个 DockerClient 实例并将参数传递下去进行解析与执行子命令。

func main() {
	// Set terminal emulation based on platform as required.
	stdin, stdout, stderr := term.StdStreams()
	logrus.SetOutput(stderr)

	dockerCli := command.NewDockerCli(stdin, stdout, stderr, contentTrustEnabled(), containerizedengine.NewClient)
	cmd := newDockerCommand(dockerCli)

	if err := cmd.Execute(); err != nil {
		if sterr, ok := err.(cli.StatusError); ok {
			if sterr.Status != "" {
				fmt.Fprintln(stderr, sterr.Status)
			}
			// StatusError should only be used for errors, and all errors should
			// have a non-zero exit status, so never exit with 0
			if sterr.StatusCode == 0 {
				os.Exit(1)
			}
			os.Exit(sterr.StatusCode)
		}
		fmt.Fprintln(stderr, err)
		os.Exit(1)
	}
}

这是 DockerClient 的结构体

type DockerCli struct {
	configFile            *configfile.ConfigFile
	in                    *InStream
	out                   *OutStream
	err                   io.Writer
	client                client.APIClient
	serverInfo            ServerInfo
	clientInfo            ClientInfo
	contentTrust          bool
	newContainerizeClient func(string) (clitypes.ContainerizedClient, error)
}

其中 newContainerizeClient 由 internal 目录下的 containerd.go 创建,主要是通过 docker.sock 文件与远程 docker server 进程进行交互,这部分通过 containerd/containerd 组件完成。

cobra Command 与 docker build 示例

cobra.Command 定义了命令、子命令的使用方法、提示、参数以及运行的函数,以下是 docker build 命令的 cobra.Command 的方式,Use 是关于 docker build 后面参数信息的信息, short 关于 build 命令简介(将在上级命令 docker 的 help 信息中展出),Args 是接受传递的参数,RunE 是要运行的函数.

// cobra.Command
	cmd := &cobra.Command{
		Use:   "build [OPTIONS] PATH | URL | -",
		Short: "Build an image from a Dockerfile",
		Args:  cli.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			options.context = args[0]
			return runBuild(dockerCli, options)
		},
	}

可以看到 RunE 传递了在 docker 入口处创建的 dockerCli ,通过给runBuild 传递参数进行校验(检查 ImageID 、本地 Dockerfile 、URL Dockerfile 、文件内容等)等。之后调用 dockerCli 完成命令

	response, err := dockerCli.Client().ImageBuild(ctx, body, buildOptions)

参考

[1]:golang 命令行库 cobra 的使用 https://www.cnblogs.com/borey/p/5715641.html

你可能感兴趣的:(docker,云计算)