Docker source code analysis-docker client startup and Command Execution

Source: Internet
Author: User

AboveDocker source code analysis-docker daemon startupThis section describes how to start the docker daemon process. Docker daemon can be considered as a docker running carrier of the server, and the carrier that actually sends a request about the docker container operation lies in the docker client. This article analyzes the process of starting and executing a request from the perspective of docker source code.


The docker client startup process is similar to that of docker daemon. First Run reexec. init (); then the flag parameter is parsed. Because the-V and-D parameters are not specified, * flversion and * fldebug are both false, and the corresponding code block is not executed; the program then obtains and verifies the flhosts information. Because the-D parameter is not specified, * fldeamon is false, and the code block of the maindaemon () method is not executed. Finally, then, the docker client is started and executed.


First, verify that the flhosts parameter contains information about multiple hosts, such as TCP: // host: Port, Unix: // path_to_socket, or FD: // socketfd, when the length of flhosts is greater than 1, that is, when there is more than one host, it is recommended to specify a host through log. By default, the first object in the flhosts information is used as the host to parse the protocol and host address. The Code is as follows:

if len(flHosts) > 1 {log.Fatal("Please specify only one -H")}protoAddrParts := strings.SplitN(flHosts[0], "://", 2)

Then, create a docker client CLI and the TLS-Related Object tlsconfig of the secure transport layer protocol. Secure transport layer (TLS) is used for the confidentiality and data integrity between two communication applications. The Protocol consists of two layers: TLS record protocol and TLS handshake protocol. The Code is as follows:

var (cli       *client.DockerClitlsConfig tls.Config)tlsConfig.InsecureSkipVerify = true

Then, if the-tlsverify parameter is specified when the docker command is executed, * fltlsverify is true, indicating that the docker client needs to load a trusted CA to verify the docker server and execute the code block:

// If we should verify the server, we need to load a trusted caif *flTlsVerify {*flTls = truecertPool := x509.NewCertPool()file, err := ioutil.ReadFile(*flCa)if err != nil {log.Fatalf("Couldn't read ca cert %s: %s", *flCa, err)}certPool.AppendCertsFromPEM(file)tlsConfig.RootCAs = certPooltlsConfig.InsecureSkipVerify = false}

The most important parameter is the * FlCA parameter, which is assigned a value during initialization in the init () method of./docker/flag. Go, as shown below:

flCa = flag.String([]string{"-tlscacert"}, filepath.Join(dockerCertPath, defaultCaFile), "Trust only remotes providing a certificate signed by the CA given here")

var (dockerCertPath = os.Getenv("DOCKER_CERT_PATH"))

const (defaultCaFile   = "ca.pem"defaultKeyFile  = "key.pem"defaultCertFile = "cert.pem")

Therefore, you can obtain * FlCA through the above information, read the corresponding ca. pem file, and add it to the attributes rootcas and insecureskipverify of the tlsconfig object.


After verifying the server and adding a trusted CA, the docker client needs to configure authentication information for subsequent sending. Add the certificates attribute to the tlsconfig object. The Code is as follows:

// If tls is enabled, try to load and send client certificatesif *flTls || *flTlsVerify {_, errCert := os.Stat(*flCert)_, errKey := os.Stat(*flKey)if errCert == nil && errKey == nil {*flTls = truecert, err := tls.LoadX509KeyPair(*flCert, *flKey)if err != nil {log.Fatalf("Couldn't load X509 key pair: %s. Key encrypted?", err)}tlsConfig.Certificates = []tls.Certificate{cert}}}

The main difference between the following is whether the secure transport layer protocol is required to initialize the CLI object of the docker client, that is, if either * fltls or * fltlsverify is true, the Secure Transport Layer Protocol is required. Otherwise, the secure transport layer protocol is not used.

if *flTls || *flTlsVerify {cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], &tlsConfig)} else {cli = client.NewDockerCli(os.Stdin, os.Stdout, os.Stderr, protoAddrParts[0], protoAddrParts[1], nil)}

The implementation of client. newdockercli () is located in./API/client/CLI. Go. The Code is as follows:

func NewDockerCli(in io.ReadCloser, out, err io.Writer, proto, addr string, tlsConfig *tls.Config) *DockerCli {var (isTerminal = falseterminalFd uintptrscheme     = "http")if tlsConfig != nil {scheme = "https"}if in != nil {if file, ok := out.(*os.File); ok {terminalFd = file.Fd()isTerminal = term.IsTerminal(terminalFd)}}if err == nil {err = out}return &DockerCli{proto:      proto,addr:       addr,in:         in,out:        out,err:        err,isTerminal: isTerminal,terminalFd: terminalFd,tlsConfig:  tlsConfig,scheme:     scheme,}}

In general, it is relatively simple to create a dockercli object. The more important dockercli attributes include proto: Transport Protocol; ADDR: Destination Address of the host, tlsconfig: Security Transport Layer Protocol configuration. If tlsconfig has content, it means you need to use the secure transport layer protocol. The scheme of the dockercli object is set to "HTTPS". In addition, you can configure input, output, and error display, the object is returned.


In./docker. Go, after the CLI object is initialized, the command specified by the user is executed. The Code is as follows:

if err := cli.Cmd(flag.Args()...); err != nil {if sterr, ok := err.(*utils.StatusError); ok {if sterr.Status != "" {log.Println(sterr.Status)}os.Exit(sterr.StatusCode)}log.Fatal(err)}

In this process, the real execution carrier is CLI. CMD (flag. ARGs ()...), this code parses and executes commands such as "docker pull XXX" and "docker search XXX.


Enter the CMD method in./API/client/CLI. Go. The Code is as follows:

// Cmd executes the specified commandfunc (cli *DockerCli) Cmd(args ...string) error {if len(args) > 0 {method, exists := cli.getMethod(args[0])if !exists {fmt.Println("Error: Command not found:", args[0])return cli.CmdHelp(args[1:]...)}return method(args[1:]...)}return cli.CmdHelp(args...)}

First, the CMD method uses the first parameter to execute the getmethod method. If the method is not found, the cmdhelp method is called. If the method is found, the method is executed, the input parameter is the first parameter from start to end. The Code is as follows:

func (cli *DockerCli) getMethod(name string) (func(...string) error, bool) {if len(name) == 0 {return nil, false}methodName := "Cmd" + strings.ToUpper(name[:1]) + strings.ToLower(name[1:])method := reflect.ValueOf(cli).MethodByName(methodName)if !method.IsValid() {return nil, false}return method.Interface().(func(...string) error), true}

The following uses the command "docker pull XXX" as an example to analyze the running of the docker client cmd. First, if the input parameters in the CMD method are "pull" and "XXX", the getmethod method has only one input parameter, which is "pull". The getmethod method returns cmdpull; execute cmdpull (ARGs [1:]...) in the CMD method. The implementation of the cmdpull method lies in the cmdpull in./API/client/command. Go.


In the specific routing XXX method, CLI is usually used to communicate with docker server. For example, cli. Stream ("Post", "/images/create? "+ V. encode (), nil, CLI. out, map [String] [] string {"X-registry-auth": registryauthheader,}), and the stream method implementation of CLI and similar call methods are located in. /API/client/utils. go. Utils. Go mainly implements how the CLI sends requests to the server in the form of httpclient, and how to use the secure transmission protocol throughout the sending process if necessary.


When the CLI request is sent and the corresponding response is received, the life cycle of one execution is over for the docker client. When you need to execute another command, you need to go through the above process again.


From the perspective of docker source code, this section analyzes the docker client startup and command execution.


Indicate the source for reprinting.

This article is more out of my own understanding, and there must be some shortcomings and errors in some places. I hope this article will be helpful to anyone who has contact with docker. If you are interested in this and have better ideas and suggestions, please contact me.

My mailbox: [email protected] Sina Weibo: @ lianzifu ruqing

Docker source code analysis-docker client startup and Command Execution

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.