// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli { //创建cli对象 cli := &DockerCli{ in: in, out: out, err: err, keyFile: clientFlags.Common.TrustKey, } //docker客户端模式的创建过程,如果需要安全认证,需要加载安全认证的证书。 cli.init = func() error { clientFlags.PostParse() configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e) } if !configFile.ContainsAuth() { credentials.DetectDefaultStore(configFile) } cli.configFile = configFile host, err := getServerHost(clientFlags.Common.Hosts, clientFlags.Common.TLSOptions) if err != nil { return err } customHeaders := cli.configFile.HTTPHeaders if customHeaders == nil { customHeaders = map[string]string{} } customHeaders["User-Agent"] = clientUserAgent() verStr := api.DefaultVersion.String() if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" { verStr = tmpStr } httpClient, err := newHTTPClient(host, clientFlags.Common.TLSOptions) if err != nil { return err } client, err := client.NewClient(host, verStr, httpClient, customHeaders) if err != nil { return err } cli.client = client if cli.in != nil { cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in) } if cli.out != nil { cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out) } return nil } return cli }
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli { cli := &DockerCli{ in: in, out: out, err: err, keyFile: clientFlags.Common.TrustKey, } cli.init = func() error { clientFlags.PostParse() configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e) } cli.configFile = configFile host, err := getServerHost(clientFlags.Common.Hosts, clientFlags.Common.TLSOptions) if err != nil { return err } customHeaders := cli.configFile.HTTPHeaders if customHeaders == nil { customHeaders = map[string]string{} } customHeaders["User-Agent"] = "Docker-Client/" + dockerversion.Version + " (" + runtime.GOOS + ")" verStr := api.DefaultVersion.String() if tmpStr := os.Getenv("DOCKER_API_VERSION"); tmpStr != "" { verStr = tmpStr } clientTransport, err := newClientTransport(clientFlags.Common.TLSOptions) if err != nil { return err } client, err := client.NewClient(host, verStr, clientTransport, customHeaders) if err != nil { return err } cli.client = client if cli.in != nil { cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in) } if cli.out != nil { cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out) } return nil } return cli }
//docker client 创建函数 // NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err. // The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config // is set the client scheme will be set to https. // The client will be given a 32-second timeout (see https://github.com/docker/docker/pull/8035). func NewDockerCli(in io.ReadCloser, out, err io.Writer, clientFlags *cli.ClientFlags) *DockerCli { cli := &DockerCli{ in: in, out: out, err: err, keyFile: clientFlags.Common.TrustKey, } cli.init = func() error { clientFlags.PostParse() hosts := clientFlags.Common.Hosts switch len(hosts) { case 0: hosts = []string{os.Getenv("DOCKER_HOST")} case 1: // only accept one host to talk to default: return errors.New("Please specify only one -H") } defaultHost := opts.DefaultTCPHost if clientFlags.Common.TLSOptions != nil { defaultHost = opts.DefaultTLSHost } var e error if hosts[0], e = opts.ParseHost(defaultHost, hosts[0]); e != nil { return e } protoAddrParts := strings.SplitN(hosts[0], "://", 2) cli.proto, cli.addr = protoAddrParts[0], protoAddrParts[1] if cli.proto == "tcp" { // error is checked in pkg/parsers already parsed, _ := url.Parse("tcp://" + cli.addr) cli.addr = parsed.Host cli.basePath = parsed.Path } if clientFlags.Common.TLSOptions != nil { cli.scheme = "https" //启用HTTPS var e error cli.tlsConfig, e = tlsconfig.Client(*clientFlags.Common.TLSOptions) if e != nil { return e } } else { cli.scheme = "http" } if cli.in != nil { cli.inFd, cli.isTerminalIn = term.GetFdInfo(cli.in) } if cli.out != nil { cli.outFd, cli.isTerminalOut = term.GetFdInfo(cli.out) } // The transport is created here for reuse during the client session. cli.transport = &http.Transport{ TLSClientConfig: cli.tlsConfig, } sockets.ConfigureTCPTransport(cli.transport, cli.proto, cli.addr) configFile, e := cliconfig.Load(cliconfig.ConfigDir()) if e != nil { fmt.Fprintf(cli.err, "WARNING: Error loading config file:%v\n", e) } cli.configFile = configFile return nil } return cli }