您的位置:首页 > 运维架构 > Docker

【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

     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 目录下 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: