一 下载docker开发镜像
Docker hub提供了一个用于docker组件自动化编译的镜像docker-dev,这个镜像自带了docker源码和docker源码编译所依赖的各种环境资源。但是这个镜像目前不再随着docker源码更新,这个镜像自带docker最新的版本为1.9.1,如果需要编译更新的docker源码,需要进行一定的适配。
镜像的pull命令:
docker pull docker-dev:tag
这里以docker-1.8.2对应镜像为例: docker pull docker-dev:1.8.2。这个docker-dev镜像较大,从docker-hub pull时需要等待一段时间。
二 获取docker源码
目前的Docker由多个组件组成,包括docker, containerd,runc。这些组件在github上都是独立的项目。可以从github上获取到这些组件源码,并在docker-dev镜像中进行编译。下面是几个组件的github地址。
1 docker
https://github.com/moby/moby/tags
2 containerd
https://github.com/containerd/containerd/tags
3 runc
https://github.com/opencontainers/runc/releases
三 搭建编译环境
从docker hub(或者国内的加速器)下载了镜像docker-dev后,可以通过docker images命令查看到这个镜像。
warmbobo@tdd:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-dev 1.8.2 d1d2969c55fe 2 years ago 1.65GB
由于docker-dev中自带的docker源码版本比较旧,而且镜像中集成的golang也不够新; 同时,镜像中集成docker源码的方式不够灵活,因而我们需要对其进行改造。
3.1 创建初始容器
通过docker run命令在docker-dev镜像上创建并进入一个容器:
warmbobo@tdd:~$ sudo docker run --name autobuild --privileged -it docker-dev:1.8.2 /bin/bash
root@e654b914ba37:/go/src/github.com/docker/docker# pwd
/go/src/github.com/docker/docker
root@e654b914ba37:/go/src/github.com/docker/docker# ls
AUTHORS Dockerfile.simple NOTICE api contrib docs image opts runconfig volume
CHANGELOG.md LICENSE README.md builder daemon experimental integration-cli pkg trust
CONTRIBUTING.md MAINTAINERS ROADMAP.md cli docker graph links project utils
Dockerfile Makefile VERSION cliconfig dockerinit hack man registry vendor
root@e654b914ba37:/go/src/github.com/docker/docker# cat VERSION
1.8.2
我们从docker-dev镜像创建了一个名为autobuild的容器,可以看到在容器中的/go/src/github.com/docker/docker目录已经集成了docker-1.8.2版本的源码。此时我们已经运行在容器中。
3.2 改造镜像
为了让这个镜像能够编译各种版本的docker源码,我们可以利用docker volume将host机器上需要编译的docker源码映射到容器的/go/src/github.com/docker/docker目录就实现不同版本的docker源码灵活编译了。
在上面创建运行着的容器中将docker-1.8.2版本的源码先删掉:
root@e654b914ba37:/go/src/github.com/docker/docker# cd ..
root@e654b914ba37:/go/src/github.com/docker# ls
docker
root@e654b914ba37:/go/src/github.com/docker# rm -rf docker/
查看我们对docker-dev镜像所做的修改:
warmbobo@tdd:~$ sudo docker diff autobuild
[sudo] password for tdd:
C /go/src/github.com/docker
D /go/src/github.com/docker/docker
然后我们在host端提交我们的修改:
warmbobo@tdd:~$ sudo docker commit autobuild docker-dev:autobuild
sha256:e230725088b4558633a628ffb392a74ca7c2b8b37d09dfb5ebb48fbace08611a
warmbobo@tdd:~$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-dev autobuild e230725088b4 8 seconds ago 1.65GB
docker-dev 1.8.2 d1d2969c55fe 2 years ago 1.65GB
这样我们就有了一个新的镜像docker-dev:autobuild,镜像中没有固定的docker源码。
3.3 创建特定版本的docker编译容器
假设我们下载了docker-1.12.6源码在/mnt/sda6/docker/moby-1.12.6目录,如下所示:
warmbobo@tdd:/mnt/sda6/docker/moby-1.12.6$ pwd
/mnt/sda6/docker/moby-1.12.6
warmbobo@tdd:/mnt/sda6/docker/moby-1.12.6$ ls
api cmd Dockerfile Dockerfile.simple hack MAINTAINERS opts reference vendor
AUTHORS container Dockerfile.aarch64 Dockerfile.windows image Makefile pkg registry VENDORING.md
builder contrib Dockerfile.armhf dockerversion integration-cli man plugin restartmanager VERSION
CHANGELOG.md CONTRIBUTING.md Dockerfile.gccgo docs layer migrate profiles ROADMAP.md volume
cli daemon Dockerfile.ppc64le errors libcontainerd NOTICE project runconfig
cliconfig distribution Dockerfile.s390x experimental LICENSE oci README.md utils
warmbobo@tdd:/mnt/sda6/docker/moby-1.12.6$ cat VERSION
1.12.6
另外,docker-dev中的golang版本也比较低,在编译较高版本的docker组件时很可能会失败,因而还需要将编译容器的golang环境也替换。
因此,我们通过docker-dev:autobuild创建的一个专门用于编译docker-1.12.6源码的容器需要映射host端的/mnt/sda6/docker/moby-1.12.6和/usr/local/go两个目录,如下所示:
warmbobo@tdd:~$ sudo docker run --name moby-1.12.6 -v /mnt/sda6/docker/moby-1.12.6:/go/src/github.com/docker/docker -v /usr/local/go/:/usr/local/go/ --privileged -it docker-dev:autobuild /bin/bash
root@1fb7707e3b24:/go/src/github.com/docker/docker# go version
go version go1.9.2 linux/amd64
root@1fb7707e3b24:/go/src/github.com/docker/docker#
这样我们就创建了用于编译host机器上/mnt/sda6/docker/moby-1.12.6处源码的容器moby-1.12.6,而且容器中golang的环境也是host主机上的较高的go1.9.2版本。
3.4 编译docker源码
按照3.3小节的步骤搭建好docker-1.12.6源码编译环境的容器后,就可以开始进行编译了,有动态和静态编译两种方式,如果编译的容器在本机上运行可以选择动态编译; 否则考虑静态编译(使用静态编译时出现一些warning,不过可暂时忽略)。下面动态编译的详细过程:
root@1fb7707e3b24:/go/src/github.com/docker/docker# hack/make.sh dynbinary
---> Making bundle: dynbinary (in bundles/1.12.6/dynbinary)
Building: bundles/1.12.6/dynbinary-client/docker-1.12.6
Created binary: bundles/1.12.6/dynbinary-client/docker-1.12.6
Building: bundles/1.12.6/dynbinary-daemon/dockerd-1.12.6
Created binary: bundles/1.12.6/dynbinary-daemon/dockerd-1.12.6
Building: bundles/1.12.6/dynbinary-daemon/docker-proxy-1.12.6
Created binary: bundles/1.12.6/dynbinary-daemon/docker-proxy-1.12.6
编译完成后,会在容器源码目录生成一个bundles目录,docker的组件都在这个目录下生成。
root@1fb7707e3b24:/go/src/github.com/docker/docker# ls -l bundles/1.12.6/dynbinary-client/
total 11530
lrwxrwxrwx 1 root root 34 Jan 21 04:26 docker -> docker-1.12.6
-rwxrwxrwx 1 root root 11801014 Jan 21 04:26 docker-1.12.6
-rwxrwxrwx 1 root root 48 Jan 21 04:26 docker-1.12.6.md5
-rwxrwxrwx 1 root root 80 Jan 21 04:26 docker-1.12.6.sha256
root@1fb7707e3b24:/go/src/github.com/docker/docker# ls -l bundles/1.12.6/dynbinary-daemon/
total 35875
lrwxrwxrwx 1 root root 46 Jan 21 04:29 docker-proxy -> docker-proxy-1.12.6
-rwxrwxrwx 1 root root 2014707 Jan 21 04:29 docker-proxy-1.12.6
-rwxrwxrwx 1 root root 54 Jan 21 04:29 docker-proxy-1.12.6.md5
-rwxrwxrwx 1 root root 86 Jan 21 04:29 docker-proxy-1.12.6.sha256
lrwxrwxrwx 1 root root 36 Jan 21 04:28 dockerd -> dockerd-1.12.6
-rwxrwxrwx 1 root root 34713852 Jan 21 04:28 dockerd-1.12.6
-rwxrwxrwx 1 root root 49 Jan 21 04:28 dockerd-1.12.6.md5
-rwxrwxrwx 1 root root 81 Jan 21 04:28 dockerd-1.12.6.sha256
四 其他组件
上面演示了docker源码的编译过程,其他相关组件containerd和runc的编译过程很类似,参考摸索即可完成。