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" }