docker源码学习之 docker version 子命令 说明: 使用的代码是  https://github.com/golang108/docker-cli.git   (tag: v24.0.6)
1. 添加容器相关的几个子命令 其中就有我们这里说到 version 子命令。
容器相关的 子命令 在这里 被加入到 corba 中去
cli/command/commands/commands.go 文件
1 2 3 4 5 6 7 8 9 func AddCommands(cmd *cobra.Command, dockerCli command.Cli) { 	cmd.AddCommand( 		system.NewVersionCommand(dockerCli), 		...... 		...... 		...... 	) } 
 
2. NewVersionCommand() 函数 1 2 3 4 func NewVersionCommand(dockerCli command.Cli) *cobra.Command { } 
 
基本上可以发现docker所有的子命令 都有个 NewXXXXCommand 的函数,cli/command/commands/commands.go 文件能一眼看到全部的。
1️⃣这个函数 主要作用 就是 初始化 cobra.Command{} 结构体 指针。然后返回这个指针。
2️⃣然后 设置 flags的解析。这里只有一个 -f、–format 选项。
通过打印 帮助可以看到 选项
1 2 3 4 5 6 7 8 9 10 11 12 13 $ ./build/docker version -h   Flag shorthand -h has been deprecated, please use --help Usage:  docker version [OPTIONS] Show the Docker version information Options:   -f, --format string   Format output using a custom template:                         'json':             Print in JSON format                         'TEMPLATE':         Print output using the given Go template.                         Refer to https://docs.docker.com/go/formatting/ for more information about formatting output with                         templates 
 
2.1 cmd := &cobra.Command{} 结构体的初始化 1 2 3 4 5 6 7 8 9 10 11 12 13 14 cmd := &cobra.Command{ 	Use:   "version [OPTIONS]", 	Short: "Show the Docker version information", 	Args:  cli.NoArgs, 	RunE: func(cmd *cobra.Command, args []string) error { 		return runVersion(dockerCli, &opts) 	}, 	Annotations: map[string]string{ 		"category-top": "10", 	}, 	ValidArgsFunction: completion.NoComplete, } 
 
1️⃣ 这里注册 runVersion(dockerCli, &opts) 函数
2️⃣Annotations中”category-top”: “10”的作用,这个和docker help显示 Common Commands 命令的排序有关系。
如下,为什么info命令排在最下面,是因为 info 这个值设置的是12,最大的。run命令排第一是因为设置的是最小的是1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ docker help  Usage:  docker [OPTIONS] COMMAND A self-sufficient runtime for containers Common Commands:   run         Create and run a new container from an image   exec        Execute a command in a running container   ps          List containers   build       Build an image from a Dockerfile   pull        Download an image from a registry   push        Upload an image to a registry   images      List images   login       Log in to a registry   logout      Log out from a registry   search      Search Docker Hub for images   version     Show the Docker version information   info        Display system-wide information 
 
在 cli/cobra.go 文件中可以看到:
1 2 3 4 func topCommands(cmd *cobra.Command) []*cobra.Command { 		省略。。。。 		return sortorder.NaturalLess(cmds[i].Annotations["category-top"], cmds[j].Annotations["category-top"]) 		省略。。。。 
 
2.2  添加 flags 1 cmd.Flags().StringVarP(&opts.format, "format", "f", "", flagsHelper.InspectFormatHelp) 
 
这里只有一个 -f、–format 选项。
3. runVersion(dockerCli , opts) 函数 3.1  opts *versionOptions 参数介绍 1 2 3 type versionOptions struct { 	format string } 
 
opts 这个参数 是 `var opts versionOptions `,  在 func NewRunCommand() 函数开头
定义的一个, 是一个结构体类型。这里面就一个 format 属性字段,和flags -f/--format 绑定的。
 
4. newVersionTemplate(string) 函数 参数 就是上面刚刚讲的 versionOptions.format 。
如果参数是空字符串,也就是没有指定 -f、–format选项,这里会使用一个 默认的模板:defaultVersionTemplate。
如果指定了  -f、–format选项,这里会使用一个 formatter.JSONFormat 的模板。
1️⃣ 默认模板打印如下格式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 $ ./build/docker version  Client:  Version:           24.0.6-6-g13466649e5  API version:       1.43  Go version:        go1.19.1  Git commit:        13466649e5  Built:             Sun Sep 24 12:54:21 2023  OS/Arch:           linux/amd64  Context:           default Server: Docker Engine - Community  Engine:   Version:          24.0.2   API version:      1.43 (minimum version 1.12)   Go version:       go1.20.4   Git commit:       659604f   Built:            Thu May 25 21:52:13 2023   OS/Arch:          linux/amd64   Experimental:     false  containerd:   Version:          1.6.21   GitCommit:        3dce8eb055cbb6872793272b4f20ed16117344f8  runc:   Version:          1.1.7   GitCommit:        v1.1.7-0-g860f061  docker-init:   Version:          0.19.0   GitCommit:        de40ad0 
 
2️⃣ json模式打印如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 { 	"Client": { 		"Version": "24.0.6-6-g13466649e5", 		"ApiVersion": "1.43", 		"DefaultAPIVersion": "1.43", 		"GitCommit": "13466649e5", 		"GoVersion": "go1.19.1", 		"Os": "linux", 		"Arch": "amd64", 		"BuildTime": "Sun Sep 24 12:54:21 2023", 		"Context": "default" 	}, 	"Server": { 		"Platform": { 			"Name": "Docker Engine - Community" 		}, 		"Components": [{ 			"Name": "Engine", 			"Version": "24.0.2", 			"Details": { 				"ApiVersion": "1.43", 				"Arch": "amd64", 				"BuildTime": "Thu May 25 21:52:13 2023", 				"Experimental": "false", 				"GitCommit": "659604f", 				"GoVersion": "go1.20.4", 				"KernelVersion": "5.4.0-150-generic", 				"MinAPIVersion": "1.12", 				"Os": "linux" 			} 		}, { 			"Name": "containerd", 			"Version": "1.6.21", 			"Details": { 				"GitCommit": "3dce8eb055cbb6872793272b4f20ed16117344f8" 			} 		}, { 			"Name": "runc", 			"Version": "1.1.7", 			"Details": { 				"GitCommit": "v1.1.7-0-g860f061" 			} 		}, { 			"Name": "docker-init", 			"Version": "0.19.0", 			"Details": { 				"GitCommit": "de40ad0" 			} 		}], 		"Version": "24.0.2", 		"ApiVersion": "1.43", 		"MinAPIVersion": "1.12", 		"GitCommit": "659604f", 		"GoVersion": "go1.20.4", 		"Os": "linux", 		"Arch": "amd64", 		"KernelVersion": "5.4.0-150-generic", 		"BuildTime": "2023-05-25T21:52:13.000000000+00:00" 	} } 
 
3️⃣自定义模板字符串打印如下:
1 2 $ docker version --format '{{ .Client.Version }} {{ .Server.Version }}' 24.0.6-6-g13466649e5 24.0.2 
 
模板引擎用的 go 自带的,text/template/template.go。
这个 双大括号的写法 和 vue 中很类似,web中目前流行有 Mustache、Hogan、doT.js、JsRender、Kendo UI Templates等。
5 newClientVersion(ctx, dockerCli) 获取 客户端的 版本信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func newClientVersion(contextName string, dockerCli command.Cli) clientVersion { 	v := clientVersion{ 		Version:   version.Version, 		GoVersion: runtime.Version(), 		GitCommit: version.GitCommit, 		BuildTime: reformatDate(version.BuildTime), 		Os:        runtime.GOOS, 		Arch:      arch(), 		Context:   contextName, 	} 	if version.PlatformName != "" { 		v.Platform = &platformInfo{Name: version.PlatformName} 	} 	if dockerCli != nil { 		v.APIVersion = dockerCli.CurrentVersion() 		v.DefaultAPIVersion = dockerCli.DefaultVersion()  // DefaultVersion of Current REST API, DefaultVersion = "1.43" 	} 	return v } 
 
其中有几个变量是在 cli/version/version.go 中定义的,然后编译的时候会加上
1 2 3 4 5 6 var ( 	PlatformName = "" 	Version      = "unknown-version" 	GitCommit    = "unknown-commit" 	BuildTime    = "unknown-buildtime" ) 
 
6 dockerCli.Client().ServerVersion(ctx) 获取 服务端的 版本信息
1 2 3 4 5 6 7 8 9 10 11 func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) { 	resp, err := cli.get(ctx, "/version", nil, nil) 	defer ensureReaderClosed(resp) 	if err != nil { 		return types.Version{}, err 	} 	var server types.Version 	err = json.NewDecoder(resp.body).Decode(&server) 	return server, err } 
 
类似的可以使用 curl 命令 发送http请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 $ curl --unix-socket /var/run/docker.sock   http://localhost/version { 	"Platform": { 		"Name": "Docker Engine - Community" 	}, 	"Components": [{ 		"Name": "Engine", 		"Version": "24.0.2", 		"Details": { 			"ApiVersion": "1.43", 			"Arch": "amd64", 			"BuildTime": "2023-05-25T21:52:13.000000000+00:00", 			"Experimental": "false", 			"GitCommit": "659604f", 			"GoVersion": "go1.20.4", 			"KernelVersion": "5.4.0-150-generic", 			"MinAPIVersion": "1.12", 			"Os": "linux" 		} 	}, { 		"Name": "containerd", 		"Version": "1.6.21", 		"Details": { 			"GitCommit": "3dce8eb055cbb6872793272b4f20ed16117344f8" 		} 	}, { 		"Name": "runc", 		"Version": "1.1.7", 		"Details": { 			"GitCommit": "v1.1.7-0-g860f061" 		} 	}, { 		"Name": "docker-init", 		"Version": "0.19.0", 		"Details": { 			"GitCommit": "de40ad0" 		} 	}], 	"Version": "24.0.2", 	"ApiVersion": "1.43", 	"MinAPIVersion": "1.12", 	"GitCommit": "659604f", 	"GoVersion": "go1.20.4", 	"Os": "linux", 	"Arch": "amd64", 	"KernelVersion": "5.4.0-150-generic", 	"BuildTime": "2023-05-25T21:52:13.000000000+00:00" }