【docker基础知识】编译Docker源码
2017-07-27 12:10
447 查看
docker的编译环境实际上是创建一个docker容器,在容器中对代码进行编译。
如果想快速的查看编译环境搭建指导,而不关注环境搭建的机制和细节,可以直接跳到最后一章“总结”。
机器上已经安装了docker,因为编译环境是个docker容器,所以要事先有docker(daemon),后面会创建个编译环境容器,在容器里面编译代码。
下载docker源码
git clone https://github.com/docker/docker.git
官方给的编译方法是make build 和 make binary等。下面先分析Makefile,看懂Makefile后,编译环境的准备流程就比较清楚了。
Makefile
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)") DOCKER_MOUNT 表示创建容器时的mount参数。因为编译环境是一个容器,会将物理机上的目录mount给容器容器,容器中该目录是编译生成docker二进制文件的目录。
DOCKER_FLAGS := docker run --rm -i --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) 创建docker容器时的命令行的一部分,包含了前面的DOCKER_MOUNT参数。
DOCKER_IMAGE := docker-dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN)) 镜像的名字是docker-dev
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)" 创建docker容器的命令行,组合了前面的DOCKER_FLAGS 和 DOCKER_IMAGE 。 从命令行中可以看出,启动容器的参数有 --rm -i --privileged,使用了环境变量,还有使用了
-v 参数把物理机 mount 给容器,在容器中编译好二进制文件后放到该目录中,在物理机上就能获得二进制文件。启动的的docker 容器镜像名字是 docker-dev。
make build来搭建编译环境,实际上是制作了一个镜像,这个镜像里会包含编译代码所需的环境。下面来介绍下这个镜像。
Dockerfile
执行make build 相当于调用docker build,使用的就是该Dockerfile。Dockerfile中的几个主要步骤:
使用 debian 作为基础镜像
安装一些编译需要的软件
创建 lvm2 目录,下载并解压安装
下载并安装 Go 1.8.3 版本
安装 GO 相关的 tools ,比如 go lint 等代码检查
安装 两个版本的 registry
安装 notary server;
安装docker-py 后面跑集成测试用的
挂盘 /var/lib/docker,设置工作目录为 /go/src/github.com/docker/docker
脚本拷贝到镜像中 /go/src/github.com/docker/docker/contrib/ ,并运行下载镜像的tar文件。这里 docker build 只是创建临时容器,运行contrib/download-frozen-image.sh 在docker build
所创建的临时的容器中下载docker镜像,有docker-in-docker容器嵌套的意思
ENTRYPOINT ["hack/dind"] 镜像运行源码目录中的 hack/dind 脚本。
COPY . /go/src/github.com/docker/docker 把物理机上的docker源码文件拷贝至镜像
download-frozen-image.sh脚本
作用是下载镜像的tar包,供后续docker load。在Dockerfile中的调用方式如下:
download-frozen-image.sh 传入参数,其中/docker-frozen-images作为base dir,下载存放路径。镜像包含了镜像名、镜像tag、镜像id。
download-frozen-image.sh 脚本中会从 https://registry-1.docker.io 下载
hack/dind脚本
对脚本的描述是 Dind: a wrapper script which allows docker to be run inside a docker container.
执行make binary 就可以编译出docker二进制文件。编译出来的二进制文件在源码目录下的 bundles文件中。
Makefile中的binary
先执行build,制作docker-dev编译环境镜像。 再执行DOCKER_RUN_DOCKER,创建容器,DOCKER_RUN_DOCKER 就是执行 docker run,使用docker-dev 镜像启动容器,并且会 mount -v 将容器生成二进制文件的路径与宿主机共享。启动的容器运行的命令行是 hack/make.sh binary 。
docker run完整的形式如下:
docker run --rm -i --privileged -e BUILDFLAGS -e DOCKER_CLIENTONLY -e DOCKER_DEBUG -e DOCKER_EXECDRIVER -e DOCKER_EXPERIMENTAL -e DOCKER_REMAP_ROOT -e DOCKER_GRAPHDRIVER -e DOCKER_STORAGE_OPTS -e DOCKER_USERLANDPROXY -e TESTDIRS
-e TESTFLAGS -e TIMEOUT -v "/home/xx/src/docker/docker/bundles:/go/src/github.com/docker/docker/bundles" -t "docker-dev:master" hack/make.sh binary
hack/make.sh脚本
创建的容器启动命令是hack/make.sh binary,参数为binary。
编译步骤总结:
make build ,在物理机上创建出一个 docker-dev 的镜像。
make binary , 使用docker-dev镜像启动一个容器,在容器中编译docker代码。默认二进制文件在 bundles 目录下
如果想快速的查看编译环境搭建指导,而不关注环境搭建的机制和细节,可以直接跳到最后一章“总结”。
前提
机器上已经安装了docker,因为编译环境是个docker容器,所以要事先有docker(daemon),后面会创建个编译环境容器,在容器里面编译代码。下载docker源码
git clone https://github.com/docker/docker.git
编译前分析
官方给的编译方法是make build 和 make binary等。下面先分析Makefile,看懂Makefile后,编译环境的准备流程就比较清楚了。Makefile
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)") DOCKER_MOUNT 表示创建容器时的mount参数。因为编译环境是一个容器,会将物理机上的目录mount给容器容器,容器中该目录是编译生成docker二进制文件的目录。
DOCKER_FLAGS := docker run --rm -i --privileged $(DOCKER_CONTAINER_NAME) $(DOCKER_ENVS) $(DOCKER_MOUNT) $(DOCKER_PORT_FORWARD) 创建docker容器时的命令行的一部分,包含了前面的DOCKER_MOUNT参数。
DOCKER_IMAGE := docker-dev$(if $(GIT_BRANCH_CLEAN),:$(GIT_BRANCH_CLEAN)) 镜像的名字是docker-dev
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)" 创建docker容器的命令行,组合了前面的DOCKER_FLAGS 和 DOCKER_IMAGE 。 从命令行中可以看出,启动容器的参数有 --rm -i --privileged,使用了环境变量,还有使用了
-v 参数把物理机 mount 给容器,在容器中编译好二进制文件后放到该目录中,在物理机上就能获得二进制文件。启动的的docker 容器镜像名字是 docker-dev。
make build
make build来搭建编译环境,实际上是制作了一个镜像,这个镜像里会包含编译代码所需的环境。下面来介绍下这个镜像。 Dockerfile
执行make build 相当于调用docker build,使用的就是该Dockerfile。Dockerfile中的几个主要步骤:
使用 debian 作为基础镜像
安装一些编译需要的软件
RUN apt-get update && apt-get install -y \ apparmor \ apt-utils \ aufs-tools \ automake \ bash-completion \ binutils-mingw-w64 \ bsdmainutils \ btrfs-tools \ build-essential \ cmake \ createrepo \ curl \ dpkg-sig \ gcc-mingw-w64 \ git \ iptables \ jq \ less \ libapparmor-dev \ libcap-dev \ libnl-3-dev \ libprotobuf-c0-dev \ libprotobuf-dev \ libsystemd-journal-dev \ libtool \ mercurial \ net-tools \ pkg-config \ protobuf-compiler \ protobuf-c-compiler \ python-dev \ python-mock \ python-pip \ python-websocket \ tar \ vim \ vim-common \ xfsprogs \ zip \ --no-install-recommends \ && pip install awscli==1.10.15
创建 lvm2 目录,下载并解压安装
ENV LVM2_VERSION 2.02.103 RUN mkdir -p /usr/local/lvm2 \ && curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \ | tar -xzC /usr/local/lvm2 --strip-components=1 # See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags # Compile and install lvm2 RUN cd /usr/local/lvm2 \ && ./configure \ --build="$(gcc -print-multiarch)" \ --enable-static_link \ && make device-mapper \ && make install_device-mapper
下载并安装 Go 1.8.3 版本
ENV GO_VERSION 1.8.3 RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \ | tar -xzC /usr/local ENV PATH /go/bin:/usr/local/go/bin:$PATH ENV GOPATH /go
安装 GO 相关的 tools ,比如 go lint 等代码检查
# Dependency for golint ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3 RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \ && (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT) # Grab Go's lint tool ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456 RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \ && (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \ && go install -v github.com/golang/lint/golint
安装 两个版本的 registry
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \ && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \ && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \ && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \ && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \ && rm -rf "$GOPATH"
安装 notary server;
ENV NOTARY_VERSION v0.5.0 RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \ && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \ && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \ && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \ go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \ && rm -rf "$GOPATH"
安装docker-py 后面跑集成测试用的
# Get the "docker-py" source so we can run their integration tests ENV DOCKER_PY_COMMIT a962578e515185cf06506050b2200c0b81aa84ef # To run integration tests docker-pycreds is required. # Before running the integration tests conftest.py is # loaded which results in loads auth.py that # imports the docker-pycreds module. RUN git clone https://github.com/docker/docker-py.git /docker-py \ && cd /docker-py \ && git checkout -q $DOCKER_PY_COMMIT \ && pip install docker-pycreds==0.2.1 \ && pip install -r test-requirements.txt
挂盘 /var/lib/docker,设置工作目录为 /go/src/github.com/docker/docker
VOLUME /var/lib/docker WORKDIR /go/src/github.com/docker/docker ENV DOCKER_BUILDTAGS apparmor seccomp selinux
脚本拷贝到镜像中 /go/src/github.com/docker/docker/contrib/ ,并运行下载镜像的tar文件。这里 docker build 只是创建临时容器,运行contrib/download-frozen-image.sh 在docker build
所创建的临时的容器中下载docker镜像,有docker-in-docker容器嵌套的意思
# Get useful and necessary Hub images so we can "docker load" locally instead of pulling COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/ RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \ buildpack-deps:jessie@sha256:85b379ec16065e4fe4127eb1c5fb1bcc03c559bd36dbb2e22ff496de55925fa6 \ busybox:latest@sha256:32f093055929dbc23dec4d03e09dfe971f5973a9ca5cf059cbfb644c206aa83f \ debian:jessie@sha256:72f784399fd2719b4cb4e16ef8e369a39dc67f53d978cd3e2e7bf4e502c7b793 \ hello-world:latest@sha256:c5515758d4c5e1e838e9cd307f6c6a0d620b5e07e6f927b07d05f6d12a1ac8d7
ENTRYPOINT ["hack/dind"] 镜像运行源码目录中的 hack/dind 脚本。
COPY . /go/src/github.com/docker/docker 把物理机上的docker源码文件拷贝至镜像
download-frozen-image.sh脚本
作用是下载镜像的tar包,供后续docker load。在Dockerfile中的调用方式如下:
download-frozen-image.sh 传入参数,其中/docker-frozen-images作为base dir,下载存放路径。镜像包含了镜像名、镜像tag、镜像id。
download-frozen-image.sh 脚本中会从 https://registry-1.docker.io 下载
hack/dind脚本
对脚本的描述是 Dind: a wrapper script which allows docker to be run inside a docker container.
make binary
执行make binary 就可以编译出docker二进制文件。编译出来的二进制文件在源码目录下的 bundles文件中。Makefile中的binary
binary: build ## build the linux binaries $(DOCKER_RUN_DOCKER) hack/make.sh binary
先执行build,制作docker-dev编译环境镜像。 再执行DOCKER_RUN_DOCKER,创建容器,DOCKER_RUN_DOCKER 就是执行 docker run,使用docker-dev 镜像启动容器,并且会 mount -v 将容器生成二进制文件的路径与宿主机共享。启动的容器运行的命令行是 hack/make.sh binary 。
docker run完整的形式如下:
docker run --rm -i --privileged -e BUILDFLAGS -e DOCKER_CLIENTONLY -e DOCKER_DEBUG -e DOCKER_EXECDRIVER -e DOCKER_EXPERIMENTAL -e DOCKER_REMAP_ROOT -e DOCKER_GRAPHDRIVER -e DOCKER_STORAGE_OPTS -e DOCKER_USERLANDPROXY -e TESTDIRS
-e TESTFLAGS -e TIMEOUT -v "/home/xx/src/docker/docker/bundles:/go/src/github.com/docker/docker/bundles" -t "docker-dev:master" hack/make.sh binary
hack/make.sh脚本
创建的容器启动命令是hack/make.sh binary,参数为binary。
总结
编译步骤总结: make build ,在物理机上创建出一个 docker-dev 的镜像。
make binary , 使用docker-dev镜像启动一个容器,在容器中编译docker代码。默认二进制文件在 bundles 目录下
相关文章推荐
- Linux从用户层到内核层系列 - TCP/IP协议栈部分系列7: 基础知识之 - Linux内核源码目录与内核编译选项
- CentOS6.5 从源码编译安装 GCC-4.9.1 全程实录《第一部分:基础知识与准备工作》
- docker基础知识
- Docker基本基础知识了解
- ucos在s3c2410上运行过程整体剖析之基础知识--关于ADS编译、链接器 .
- Docker基础知识(一)
- ant 脚本编译基础知识
- Linux内核模块的编译基础知识
- 安卓源码总体结构(1)基础知识汇总
- 编译原理--文法基础知识
- 安卓源码总体结构(2)基础知识汇总
- 安卓源码总体结构(2)基础知识汇总
- docker最新代码源码编译
- C#基础语言知识--编译和执行过程(一)
- shell脚本的基础知识1:基本脚本的编译
- Docker 教程之获取镜像基础知识详解
- 关于编译,链接及库的一些基础知识 标 题:关于编译,链接及库的一些基础知识
- Java基础 (一)javac 指定编码,解决DOS下java源码GBK编译不通过
- 基于mjpg-streamer-r63的源码分析之:基础知识详细解释[一]
- docker基础理论知识