前面分析了使用cobra创建client,下面选取一条命令分析下client端如何执行
命令的处理都在cli目录之下,以 image 的 pull 为例
/cli/command/commands/commands.go AddCommands函数增加命令注册
pull命令在 image.NewImageCommand(dockerCli) 里面
/cli/command/image/cmd.go 里定义了增加 pull命令 NewPullCommand(dockerCli),
/cli/command/image/pull.go 定义了pull命令
unc NewPullCommand(dockerCli *command.DockerCli) *cobra.Command {
var opts pullOptions
cmd := &cobra.Command{
Use: "pull [OPTIONS] NAME[:TAG|@DIGEST]",
Short: "Pull an image or a repository from a registry",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.remote = args[0]
return runPull(dockerCli, opts) //pull命令的执行
},
}
flags := cmd.Flags()
flags.BoolVarP(&opts.all, "all-tags", "a", false, "Download all tagged images in the repository")
command.AddTrustVerificationFlags(flags)
return cmd
}
pull命令的运行也在改文件内,省略一些异常处理之后
func runPull(dockerCli *command.DockerCli, opts pullOptions) error {
distributionRef, err := reference.ParseNormalizedNamed(opts.remote) // 根据命令字符串获取domain的一些信息
// Resolve the Repository name from fqn to RepositoryInfo
repoInfo, err := registry.ParseRepositoryInfo(distributionRef) //registry/config.go 调用newRepositoryInfo创建repsitory仓库的一些信息
ctx := context.Background() //上下文
authConfig := command.ResolveAuthConfig(ctx, dockerCli, repoInfo.Index) // registry.go 创建鉴权的数据
requestPrivilege := command.RegistryAuthenticationPrivilegedFunc(dockerCli, repoInfo.Index, "pull") // registry.go 鉴权的函数
// Check if reference has a digest
_, isCanonical := distributionRef.(reference.Canonical)
if command.IsTrusted() && !isCanonical {
err = trustedPull(ctx, dockerCli, repoInfo, distributionRef, authConfig, requestPrivilege) // trust.go 先获取Repository信息,在Repository获取所有Target信息,遍历target最终还是调用imagePullPrivileged
} else {
err = imagePullPrivileged(ctx, dockerCli, authConfig, reference.FamiliarString(distributionRef), requestPrivilege, opts.all) //trust.go 该函数pull image 并且将结果回显
}
}
创建repoinfo
//config := newServiceConfig(ServiceOptions{})
func newRepositoryInfo(config *serviceConfig, name reference.Named) (*RepositoryInfo, error) {
index, err := newIndexInfo(config, reference.Domain(name))
if err != nil {
return nil, err
}
official := !strings.ContainsRune(reference.FamiliarName(name), '/')
return &RepositoryInfo{
Name: reference.TrimNamed(name),
Index: index,
Official: official,
}, nil
}
// imagePullPrivileged pulls the image and displays it to the output
func imagePullPrivileged(ctx context.Context, cli *command.DockerCli, authConfig types.AuthConfig, ref string, requestPrivilege types.RequestPrivilegeFunc, all bool) error {
encodedAuth, err := command.EncodeAuthToBase64(authConfig)
options := types.ImagePullOptions{
RegistryAuth: encodedAuth,
PrivilegeFunc: requestPrivilege,
All: all,
}
responseBody, err := cli.Client().ImagePull(ctx, ref, options) // client/image_pull.go 关键一句 cli.tryImageCreate(ctx, query, options.RegistryAuth)
defer responseBody.Close() // 执行完之后关闭
return jsonmessage.DisplayJSONMessagesToStream(responseBody, cli.Out(), nil) // 显示json信息
}
func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
return cli.post(ctx, "/images/create", query, nil, headers)
}