This article is the same as the previous one, but with a few more analytical steps.

First, environment construction

To compile docker, docker software needs to be pre-installed on the host. When compiling the docker source code, a Docker image will be built and run, and the build operation will be carried out in this container. Since this container already contains the Go language environment, the host does not need to install Golang. Host system: Ubuntu 16.04 64-bit Host Docker Version:

Docker -v Docker version 17.10.0 -CE, build F4FFd25Copy the code

Two, download the source code

Docker’s github website is github.com/docker/dock… . Docker develops at a pace of one release per month. The naming rule is year-month-CE, where CE indicates the community version. As of this writing, the latest version is V18.02.0-CE, but the rc version of the next version, V18.03.0, has been released. The main branch version is V18.03.0-CE-dev (with dev indicating development stage), and the compiled version of this article is V18.03.0-CE-dev. Distributions can be downloaded at github.com/docker/dock… This compilation of the source code, no actual path irrelevant. Download the source code:

git clone https://github.com/docker/docker-ce
Copy the code

Enter the docker-ce directory:

cd docker-ce
Copy the code

Third, the compilation process

This section compiles the main branch code of Docker-CE. After analysis, its compilation script is modified and adjusted to accelerate the compilation time.

The Makefile analysis

Here we start by tracing the top Makefile to the platform-specific build Makefile. This is the Makefile for the docker-ce project directory. This is the Makefile for the Docker-ce project directory.

.PHONY: deb
deb: ## build deb packages
    $(MAKE) VERSION=$(VERSION) CLI_DIR=$(CLI_DIR) ENGINE_DIR=$(ENGINE_DIR) -C $(PACKAGING_DIR) deb
Copy the code

By default, a Makefile is executed in the Components/Packaging/deb directory. The Makefile is compiled with the following commands:

deb: ubuntu debian raspbian
Copy the code

The Ubuntu platform, in turn, involves two distributions:

ubuntu: ubuntu-xenial ubuntu-trusty
Copy the code

For Ubuntu-Xenial, compile the command:

ubuntu-xenial: ## build ubuntu xenial deb packages
    docker build -t debbuild-$@/$(ARCH) -f $(CURDIR)/$@/Dockerfile.$(ARCH) .
    docker run --rm -i \
        -e DEB_VERSION=$(DEB_VERSION) \
        -e VERSION=$(VERSION) \
        -e DOCKER_GITCOMMIT=$(GITCOMMIT) \
        -v $(CURDIR)/debbuild/$@:/build \
        -v $(ENGINE_DIR):/engine \
        -v $(CLI_DIR):/cli \
        -v $(CURDIR)/systemd:/root/build-deb/systemd \
        debbuild-$@/$(ARCH)
    $(CHOWN) -R $(shell id -u):$(shell id -g) debbuild/$@
Copy the code

Build an image using docker build, then run the image, set the environment variables (VERSION, etc.), and mount the directory ($(ENGINE_DIR):/engine, etc.). The command executed is the default docker image command. To build a Docker image, run the following command:

docker build -t debbuild-$@/$(ARCH) -f $(CURDIR)/$@/Dockerfile.$(ARCH) .
Copy the code

Debbuild – @/@/@/(ARCH) debbuild- Ubuntu-Xenial /x86_64 If -f specifies Dockerfile, it is Ubuntu-xenial/dockerfile.x86_64. Ockerfile.x86_64 needs to visit Golang.org to download the Go language installation package, the website is generally not accessible, so you need to think of other methods.

The compilation process

As can be seen from dockerfile.x86_64, the default execution script is build-deb, which is located in the same directory as Makefile, and roughly consists of compiling 4 components, compiling docker source code, and copying the generated file to the specified directory. Details will not be elaborated in this article.

Modify the compilation process

In the process of compiling docker source code, docker image will be built every time. In Docker, four necessary component source codes need to be cloned from Github.com (and compiled) every time. This process is necessary at the beginning, but if only individual source codes need to be modified for compilation in actual development, Run a complete process to show more tedious. The idea of modification is as follows: pre-make the Docker containing the GO language environment (singula/docker-dev has been made), and then make the required image for compilation based on this Docker image. Mount the compiled component source directory to the host directory so that you do not need to download it from the network every time.

Makefile Makefile Makefile Makefile Makefile Makefile Makefile Makefile Makefile Makefile Makefile Makefile

# Build mydeb for Ubuntu-xenial (16.04).PHONY: mydebmydeb: ## build deb packages $(MAKE) VERSION=$(VERSION) CLI_DIR=$(CLI_DIR) ENGINE_DIR=$(ENGINE_DIR) -C $(PACKAGING_DIR)/deb -f myMakefile ubuntu-xenialCopy the code

Create myMakefile from Makefile: components, packaging, deb

.PHONY: xenial_dockerxenial_docker: ## build the docker docker build -t debbuild-ubuntu-xenial/$(ARCH) -f $(CURDIR)/ubuntu-xenial/myDockerfile.$(ARCH) .. PHONY: ubuntu-xenialubuntu-xenial: ## build ubuntu xenial deb packages mkdir -p $(CURDIR)/src/tini $(CURDIR)/src/libnetwork \ $(CURDIR)/src/runc $(CURDIR)/src/containerd docker run --rm -i \ -e DEB_VERSION=$(DEB_VERSION) \ -e VERSION=$(VERSION) \ -e DOCKER_GITCOMMIT=$(GITCOMMIT) \ -v $(CURDIR)/debbuild/$@:/build \ -v $(ENGINE_DIR):/engine \ -v $(CLI_DIR):/cli \ -v $(CURDIR)/systemd:/root/build-deb/systemd \ -v $(CURDIR)/src/tini:/go/tini \ -v $(CURDIR)/src/libnetwork:/go/src/github.com/docker/libnetwork \ -v $(CURDIR)/src/runc:/go/src/github.com/opencontainers/runc \ -v $(CURDIR)/src/containerd:/go/src/github.com/containerd \ debbuild-$@/$(ARCH) /root/build-deb/mybuild-deb $(CHOWN) -R $(shell id -u):$(shell id -g) debbuild/$@ cp $(CURDIR)/debbuild/$@/*.deb $(TOP_DIR)Copy the code

This file separates building Docker from compiling, builds the part, and mounts the component directory required for compiling to the SRC directory in the deb’s sibling directory. Finally, copy the generated DEB package to the project directory. Create the mybuild-deb file by referring to the compilation script build-deb. Will TMP_GOPATH = “/ go” hack/dockerfile/install/install. Sh $component is modified to TMP_GOPATH = “/ go” hack/dockerfile myinstall/install. Sh $component. In components\engine\hack\dockerfile, copy install to myinstall and modify the file: Installer, proxy. Installer, Runc. Installer, and Tini. installer. Modified git Clone logic. Take tini.installer as an example. The original content is:

TINI_COMMIT=949e6facb77383876aeff8a6944dde66b3089574install_tini() {    echo "Install tini version $TINI_COMMIT"    git clone https://github.com/krallin/tini.git "$GOPATH/tini"    cd "$GOPATH/tini"    git checkout -q "$TINI_COMMIT"    cmake .    make tini-static    mkdir -p ${PREFIX}    cp tini-static ${PREFIX}/docker-init}
Copy the code

Modified for

TINI_COMMIT=949e6facb77383876aeff8a6944dde66b3089574install_tini() {    echo "Install tini version $TINI_COMMIT"        if [ ! -d $GOPATH/tini/.git ]; then        echo "will clone tini..."        git clone https://github.com/krallin/tini.git "$GOPATH/tini"    else        echo "tini exist..."    fi        cd "$GOPATH/tini"    git checkout -q "$TINI_COMMIT"    cmake .    make tini-static    mkdir -p ${PREFIX}    cp tini-static ${PREFIX}/docker-init}
Copy the code

That is, it determines whether tini has been downloaded, and if so, it will not be downloaded. If not, download it. The same goes for other files.

Compile and generate files

Enter make mydeb in the docker-ce directory to compile. The resulting installation package is in the same directory. If you have never compiled Docker-CE, the compilation will take about 20~30 minutes (approximately, depending on the network and machine performance). If you have compiled Docker-CE, modify the source code and compile it again, it will only take a few minutes to more than 10 minutes. Greatly reduces compilation time. Install the deb package to your local computer or another Ubuntu system and run the following command to install it:

# DPKG -i docker - ce_18. 04.0 ~ ce ~ dev ~ git20180312.035344.0.37 dff31-0 ~ ubuntu_amd64. DebCopy the code

Verify the version number:

# Docker-vdocker version 18.04.0-ce-dev, build 2b42807Copy the code

At this point, docker compilation ends.

note

The method used in this paper takes into account that there is no conflict with the official Docker source code, but when merging, we should pay attention to the modified files mentioned in this paper. Whether there is a better way to do it is to wait until it is discovered.