Docker run performs a stream (in volume, network, and libcontainer)

[Editor's Note] Often we are used to using Docker run to execute a Docker container, so what do Docker do when we execute Docker run? This article describes the principle of Docker run by following the implementation of the Docker run (Docker 1.9 version), by introducing the use and configuration of volume, network, and libcontainer.

@Container container technology conference will be held on June 4 at the Shanghai Everbright Convention and Exhibition Center International Hotel, from Rancher, Ctrip, PPTV, ants gold clothes, Jingdong, Zhejiang Mobile, Haier Electric, only goods, eBay, The technical person in charge of the company will bring practical experience to share, before May 7 to buy tickets only 438 yuan, welcomed the welcome, the United States, the United States, the United States, the United States, the United States, Interested students snapped up.

First, the user enters the docker run through the Docker client to create a container that is running. Docker client main job is to parse the user to provide a series of parameters, respectively, to send such two requests:

  "POST", "/ containers / create?" + ContainerValues 
"POST", "/containers/"+createResponse.ID

So that the client's work will be completed, it is clear that client doing little things, mainly responsible for sending requests to the Docker daemon. However, through the client sent two requests, we can naturally put the docker run the entire implementation process is divided into create and start two stages. The following figure docker run time points for each key event in the docker run . Here I will be from the two stages and the following chart, the implementation of the docker run process introduced.

1 Create phase

This stage of the Docker daemon's main job is to submit the POST form of the client analysis and finishing, access to a portable configuration parameters config and non-portable configuration structure hostconfig. Then the daemon will call the daemon.newContainer function to create a basic container object, and config and hostconfig information stored in the container object. Of course, this time the container object is not a specific physical container, which contains all the user-specified parameters and Docker generated some of the default configuration information. Finally, the Docker will JSON code the container object, and then save it to its corresponding state file.

After the above process is complete, the basic configuration information of a container is completely available, and the user can use the docker inspect to view the various configuration information corresponding to the container.

2 start phase

After the completion of the create phase, the client will then send the start request to start a real physical container. When the Docker daemon receives the start request, it will use the various configuration parameters in the container object configured in the create phase to complete the registration of the volume drop, the creation and creation of the container network, and the start of the physical container. The following is a brief introduction to the container's network environment creation process.

2.1 volume mount point registration

The Docker daemon, when configuring hostconfig to the container configuration information, invokes the daemon.registerMountPoints function to register the volume-related information in the POST form provided by the client and store it in the container's configuration information in the form of mountpoint, When the physical container will be mounted.

Volume mount points can be divided into two categories, one for the use of other containers in the mount point, another type of user-specified binding mount. Here we look at the two volume mount point registration process.

  • 1. Use the mount point in other containers: When registering this type of mount point, first use the id of the container to find the corresponding structure in the Docker daemon. And then traverse all of the mount points, and all of the mount point information are registered into the current container structure.
  • 2. User-specified binding mount: The user-specified binding mount can be in the format of Source Path: Destination Path or Name: Destination Path. If the user enters a parameter that is the format of the Source Path: Destination Path, the daemon resolves the Source Path and Destination Path, and uses them to register the corresponding mount point. If the user enters the name of the Name: Destination Path format, then the daemon will find whether the user-provided Name has a corresponding point of use with the docker volume has been created, if so, will use the mount point Of the information and the user to provide the Destination Path to the container mount point registration. If the Name does not have a corresponding mount point in the daemon, the daemon will create a directory in its default folder as the Source Path in the mount point and then use the user-supplied Destination Path and the self-created Source Path The registration point of this container is registered.

After the registration of the mount point has been completed, the daemon updates all the mount point information to the container's configuration information for subsequent use.

2.2 network creation

The Docker daemon uses the network-related parameters of the POST form provided by the client to create and configure the container network stack by calling the daemon.initializeNetworking function. Daemon.initializeNetworking function through the Docker network dependency library (ie libnetwork) a series of calls to complete the container network stack creation and configuration work.

To understand the execution flow of the Docker container's network, first understand the three core concepts in libnetwork.

  • Sandbox: A sandbox contains information about a container network stack. The sandbox can manage the interface, routing, and DNS settings of the container. The sandbox implementation can be a Linux Network Namespace, a FreeBSD Jail, or a similar mechanism. A sandbox can have multiple endpoints and multiple networks.
  • Endpoint: An endpoint can join a sandbox and a network. The implementation of the endpoint can be veth pair, Open vSwitch internal port or similar device. An endpoint can belong to only one network and belong to only one sandbox.
  • Network A network is a set of endpoints that can communicate directly with each other. The implementation of the network can be Linux bridge, VLAN, and so on. A network can contain multiple endpoints.

Clear the above three core concepts, we from the Docker source point of view and through the default Docker network mode (bridge mode) to look at the container network stack creation process.

  • After the Docker daemon is started, it creates a default network whose essential job is to create a default bridge called docker0.
  • After the default bridge is determined, the daemon calls container.BuildCreateEndpointOptions to create the endpoint's configuration information for this container. And then call Network.CreateEndpoint use the above configuration information to create the corresponding endpoint. In bridge mode, libnetwork creates a device that is a veth pair. Libnetwork calls netlink.LinkAdd (veth) to create a veth pair, one of the veth devices is added to the docker0 bridge, the other is prepared for the sandbox.
  • The next daemon calls daemon.buildSandboxOptions to create the sandbox for this container, and then calls Network.NewSandbox to create a new sandbox that belongs to this container. After receiving the request to create the sandbox, libnetwork uses the system call to create a new netns for the container and writes the path of the netns back to the corresponding container's configuration information for subsequent use.
  • Finally, the daemon calls ep.Join (sb) to add the endpoint to the container's corresponding sandbox. First add the endpoint to the container corresponding to the sandbox, and then the endpoint of the ip information and gateway and other information configuration, and all the information updated to the corresponding container configuration information.

2.3 container creation and startup

After completing the various preparations for creating the container, the Docker daemon completes the container creation and startup through a series of calls to libcontainer. Libcontainer is the Docker runtime library, which can be created and run by a caller's configuration parameters. Here's how a Docker uses the parameters of the previously configured structure, created and run via libcontainer A container of

2.3.1 Create logical container Container and logical process process

The so-called logical container and logical process process is not really running the container and process, but libcontainer defined in the structure. The logical container container contains various configuration information such as namespace, cgroups, device, and mountpoint. Logical process process contains the container to run the instructions to its parameters and environment variables.

The Docker daemon calls execdriver.Run to complete a series of interactive work with libcontainer. First, all the parameters associated with the new container will be loaded into the structure config that can be used by libcontainer. Then use config as a parameter to call libcontainer.New () to generate the factory factory used to generate the container. And then call factory.Create (config), will generate a config will contain the logical container container. Then call newProcess (config) to config in the container on the command to run the relevant information to fill into the process structure, the structure is the logical process process. Use container.Start (process) to start the logical container.

2.3.2 Start the logical container container

The Docker daemon calls linuxContainer.Start to start the logical container. The main job of this function is to call newParentProcess () to generate the parentprocess instance (structure) and for the runC and the container init process of communication between the pipeline.

In the parentprocess instance, there is a very important field that is cmd, except that there are pipes and various basic configurations that record the future process of communicating with the container.

The cmd field is a structure defined in the os / exec package. Os / exec package is mainly used to create a new process, and in the process of the implementation of the specified order. Developers can import the os / exec package in the project, then populate the cmd structure, the path and program name of the program to be run, the parameters required for the program, the environment variables, the properties of the various operating systems, and the extended files Descriptors and so on.

In Docker, the program fills the application path field of cmd with / proc / self / exe (the application itself, Docker). The parameter field Args is filled with init, indicating that the container is initialized. The SysProcAttr field is populated with attributes such as the namespace (which includes the netns path mentioned earlier) required for various Dockers.

Then call parentprocess.cmd.Start () to start the init process in the physical container. Next, the process number of the init process in the physical container is added to the Cgroup control group to implement resource control for the processes in the container. And then send the configuration parameters through the pipeline to the init process. Finally, through the pipeline waiting for the init process according to the above configuration to complete all the initialization work, or an error exit.

2.3.3 Configuration and creation of physical containers

The init process in the container first calls the StartInitialization () function to receive various configuration parameters from the parent process through the pipe. The container is then configured as follows:

  • 1. The init process will be added to its specified namespace, where the init process will be added to the previously created netns, so init process has its own independent network stack, complete the network creation and configuration of the last step.
  • 2. Set the session ID of the process.
  • 3. Use the system call, will be registered in front of the mount point all the physical host, so that the completion of the volume to create.
  • 4. Mount the file system in the specified directory and switch the root directory to the newly mounted file system. Set hostname, load profile information.
  • 5. Finally use the exec system call to execute the program specified by the user in the container.

This completes the creation and startup of a container.


Author Gao Xianglin, Zhejiang University SEL laboratory graduate, currently in the cloud platform team engaged in scientific research and development work. Zhejiang University team PaaS, Docker, large data and mainstream open source cloud computing technology has in-depth research and secondary development experience, the team is now part of the community will contribute to the technical articles, hoping to help readers.

    Heads up! This alert needs your attention, but it's not super important.