构建方式
Kubernetes的构建方式可以分为3种,分别是本地环境构建、容器环境构建、Bazel环境构建。
Kubernetes构建方式:
- 本地环境构建
1) make
2) make all - 容器环境构建
1) make release
2) make quick-release - Bazel环境构建
1) make bazel-build
下面将详细介绍前两种构建方式:
本地环境构建
执行make或者make all命令,会编译Kubernetes的所有组件,组件二进制文件输出的相对路径是_output/bin。如果我们需要对Makefile的执行过程进行调试,可以在make命令后面加-n参数,输出但不执行所有执行命令,这样可以展示更详细的编译构建过程。假设我们想单独构建某个组价,如kubectl组件,则需要指定WHAT参数。命令示例如下:
make WHAT=cmd/kubectl
Makefile是一个非常自动化构建工具,可以用来构建和测试Go语言的应用程序,Makefile还适用于大多数编程语言,在Kubernetes的源码根目录中,有两个与Makefile相关的文件,功能分别如下:
- Makefile:顶层Makefile文件,描述了整个项目所有代码文件的编译顺序、编译规则及编译后的二进制文件输出等。
- Makefile.generated_file:描述了代码生成的逻辑。
本地构建过程
通过调用hack/make-rules/build.sh脚本开始构建组件,传入要构建的组件名称,不指定组件名称则构建所有组件。hack/make-rules/build.sh代码示例如下:
kube::golang::build_binaries "$@"
build_binaries接收构建的组件名称,设置构建所需要的环境及一些编译时所需的Go flags选项,然后通过go install构建组件:
go install "${build_args[@]}" "$@"
在go install命令执行完成后,二进制输出的目录为_output/bin。
最后,可以使用make clean命令来清理构建环境。
容器环境构建
通过容器(Docker)进行Kubernetes构建也非常简单,Kubernetes提供了两种容器环境下得构建方式:make release 和make quick-release,它们之间的区别如下:
- make release:构建所有目标平台(Darwin、Linux、Windows),构建过程会比较久,并同时执行单元测试过程。
- make quick-release:快速构建,只构建当前平台,并略过单元测试过程。
Kubernetes容器环境构建流程:
构建环境的配置及验证:kube::build::verify_prereqs
构建容器镜像:kube::build::build_image
构建代码:kube::build::run_build_command make cross
将文件从容器复制到主机:kube::build::copy_output
打包:kube::release::package_tarballs
在容器环境构建过程中,有多个容器镜像参与其中,分别介绍如下:
- build 容器(kube-cross):即构建容器,在该容器中会对代码文件执行构建操作,完成后会被删除。
- data容器:即存储容器,用于存放构建过程中所需要的的所有文件。
- raync容器:即同步容器:用于在容器和主机之间传输数据,完成后会被删除。
下面介绍一下Kubernetes容器环境构建过程。
1.kube::build::verfy_prereqs
进行构建环境的配置及验证。该过程会检查本机是否安装了Docker容器环境,对于Darwin平台,该过程会检查本机是否安装了docker-machine环境。
2.kube::build::build_image
根据Dockerfile文件构建容器镜像。Dockerfile文件来源于build/build-image/Dockerfile,代码示例如下:
代码路径:build/common.sh
function kube::build::build_image() {
mkdir -p "${LOCAL_OUTPUT_BUILD_CONTEXT}"
...
cp "${KUBE_ROOT}/build/build-image/Dockerfile" "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile"
cp "${KUBE_ROOT}/build/build-image/rsyncd.sh" "${LOCAL_OUTPUT_BUILD_CONTEXT}/"
dd if=/dev/urandom bs=512 count=1 2>/dev/null | LC_ALL=C tr -dc 'A-Za-z0-9' | dd bs=32 count=1 2>/dev/null > "${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password"
chmod go= "${LOCAL_OUTPUT_BUILD_CONTEXT}/rsyncd.password"
kube::build::update_dockerfile
kube::build::set_proxy
kube::build::docker_build "${KUBE_BUILD_IMAGE}" "${LOCAL_OUTPUT_BUILD_CONTEXT}" 'false'
...
kube::build::ensure_data_container
kube::build::sync_to_container
}
构建容器镜像的流程如下:
- 通过mkdir命令创建构建镜像的文件夹(即_output/images/...)。
- 通过cp命令复制构建镜像所需的相关文件,如Dockerfile文件和rsyncd同步脚本等。
- 通过kube::build::docker_build函数,构建容器镜像。
- 通过kube::build::ensure_data_container函数,运行存储容器并挂载Volume。
- 通过kube::build::sync_to_container函数,运行同步容器并挂载存储容器的Volume,然后通过rsnyc命令同步Kubernetes源码到存储容器的Volume。
3.kube::build::run_build_command make cross
此时,容器构建环境已经准备好,下面开始运行构建容器并在构建容器内部执行构建Kubernetes源码的操作,代码示例如下:
代码路径:build/common.sh
function kube::build::run_build_command_ex() {
...
local detach=false
...
"${docker_cmd[@]}" "${cmd[@]}"
if [[ "${detach}" == false ]]; then
kube::build::destroy_container "${container_name}"
fi
}
在执行kube::build::run_build_command_ex函数中,通过${docker_cmd[@]}""${cmd[@]}
命令执行构建操作(即在容器内执行make cross 命令)。容器内的构建过程与本地环境下的构建过程相同。其中构建平台有KUBE_SUPPORTED_SERVER_PLATFORMS变量控制,代码示例如下:
代码路径:hack/lib/golang.sh
readonly KUBE_SUPPORTED_SERVER_PLATFORMS=(
linux/amd64
linux/arm
linux/arm64
linux/s390x
linux/ppc64le
)
构建的组件由KUBE_SERVER_TARGETS变量控制,代码示例如下:
代码路径:hack/lib/golang.sh
kube::golang::server_targets() {
local targets=(
cmd/kube-proxy
cmd/kube-apiserver
cmd/kube-controller-manager
cmd/kubelet
cmd/kubeadm
cmd/kube-scheduler
vendor/k8s.io/kube-aggregator
vendor/k8s.io/apiextensions-apiserver
cluster/gce/gci/mounter
)
echo "${targets[@]}"
}
IFS=" " read -ra KUBE_SERVER_TARGETS <<< "$(kube::golang::server_targets)"
4.kube::build::copy_output
使用同步容器,将编译后的代码文件复制到主机上。
5.kube::release::package_tarballs
进行打包,将二进制文件打包到_output目录中。
最终,代码文件以tar.gz压缩包的形式输出至_output/release-tars文件夹。