大型软件(linux,android .etc)通常都有本身的构建系统,k8s 也不例外,本文简要介绍 k8s 构建系统linux
以 quick-release 为例,在命令行执行如下命令android
# make quick-release
make 在源代码根目录 Makefile 文件中定位到 quick-release 目标,该目标的动做是执行 build/release.sh 脚本git
# kubernetes/Makefile .PHONY: release-skip-tests quick-release ifeq ($(PRINT_HELP),y) release-skip-tests quick-release: @echo "$$RELEASE_SKIP_TESTS_HELP_INFO" else release-skip-tests quick-release: KUBE_RELEASE_RUN_TESTS = n release-skip-tests quick-release: KUBE_FASTBUILD = true release-skip-tests quick-release: build/release.sh <--- 执行 kubernetes/build/release.sh endif
release.sh 将构建过程拆分红一个个步骤,每一个步骤对应一个 shell functiondocker
# kubernetes/build/release.sh ... kube::build::verify_prereqs kube::build::build_image kube::build::run_build_command make cross ... kube::build::copy_output kube::release::package_tarballs
verify_prereqs 对构建环境进行检查,好比是否缺乏一些工具软件
build_image 建立构建须要的 docker 镜像 ???
run_build_command make cross 启动容器,运行 make cross
copy_output, package_tar 处理构建生成的各个文件shell
这里比较有意思的是 k8s 使用 docker 容器进行构建,多是为了交叉编译吧dom
kube::build::build_image 方法构建基础镜像,同步 kubernetes 源代码到 data container(数据卷容器)工具
function kube::build::build_image() { mkdir -p "${LOCAL_OUTPUT_BUILD_CONTEXT}" # Make sure the context directory owned by the right user for syncing sources to container. chown -R ${USER_ID}:${GROUP_ID} "${LOCAL_OUTPUT_BUILD_CONTEXT}" cp /etc/localtime "${LOCAL_OUTPUT_BUILD_CONTEXT}/" # 准备镜像构建所需文件 cp build/build-image/Dockerfile "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile" cp 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' ... # 构建数据卷镜像,注意 ensure 这个词~数据卷镜像是能够复用的 kube::build::ensure_data_container # 同步 kubernetes 源代码到数据卷镜像 kube::build::sync_to_container }
k8s 构建过程当中使用了如下几种容器:学习
上文说到 k8s 构建的时候会启动一个容器运行 rsyncd 服务,将 k8s 源代码同步到数据卷容器,那么源代码码会被同步到哪里呢?ui
# kubernete/build/common.sh function kube::build::sync_to_container() { kube::log::status "Syncing sources to container" kube::build::start_rsyncd_container kube::build::rsync \ --delete \ --filter='H /.git' \ --filter='- /.make/' \ --filter='- /_tmp/' \ --filter='- /_output/' \ --filter='- /' \ --filter='H zz_generated.*' \ --filter='H generated.proto' \ "${KUBE_ROOT}/" "rsync://k8s@${KUBE_RSYNC_ADDR}/k8s/" }
kube::build::rsync 方法将 KUBE_ROOT 目录下的源代码同步到 k8s@${KUBE_RSYNC_ADDR}/k8s/命令行
查看 rsync 配置文件能够知道 k8s 这个虚拟目录对应的实际目录
# kubernetes/build/build-image/rsyncd.sh ... VOLUME=${HOME} cat <<EOF >"${CONFFILE}" pid file = ${PIDFILE} use chroot = no log file = /dev/stdout reverse lookup = no munge symlinks = no port = 8730 [k8s] numeric ids = true $USER_CONFIG hosts deny = * hosts allow = ${ALLOW} ${ALLOW_HOST-} auth users = k8s secrets file = ${SECRETS} read only = false path = ${VOLUME} <-- k8s 对应的路径 ${VOLUME} = ${HOME} filter = - /.make/ - /_tmp/ EOF
这个 HOME 变量通常指向 用户主目录,可是从 go语言工程目录结构 来看 HOME 应该指向相似 $GOPATH/src/k8s.io/kubernetes 的目录,因此经验和直觉告诉咱们确定有什么地方设置了 HOME 变量,经过搜索源代码,证明确实如此
# kubernetes/build/build-image/Dockerfile ... ENV HOME /go/src/k8s.io/kubernetes WORKDIR ${HOME} ...
经过分析 k8s 构建系统,能够学习像 Google 这样的大厂是如何规划大型软件工程结构,构建,发布