国内环境下 Kubernetes 源码编译及运行

1、kubernete 源码编译介绍

我们知道,kubernetes 源码编译,分为本地二进制可执行文件编译和 docker 镜像编译两种。之前演示的 minikube 方式kubeadm 方式安装,都是基于第二种 docker 镜像方式运行,当然也可以基于二进制文件方式安装,不管哪种方式,都是直接使用并不需要修改任何 k8s 代码。不过当我们有特殊需求时,比如需要修改 kube-proxy 对 service 的代理逻辑,kube-scheduler 对 pod 的调度逻辑等,这个时候就需要修改 k8s 源码了,为了让修改的代码生效,就需要对 k8s 代码执行编译了。当然 k8s 也为我们提供了 CRD 等可扩展插件,在不修改 k8s 源码的基础上实现自定义功能,但是对于一些底层逻辑策略需要修改的话,还是办不到的。

2、环境、软件准备

本次演示环境,我是在虚拟机 Linux Centos7 系统上操作,以下是安装的软件及版本:

  • Oracle VirtualBox: 5.1.20 r114628 (Qt5.6.2)
  • Linux: CentOS Linux release 7.3.1611 (Core)
  • Docker: 18.06.1-ce
  • Golang: go1.11.5
  • Kubernetes: v1.13.5

注意:因为 kubernetes 源码是由 go 语言编写的,所以要编译其源码,需要安装 go 环境,若我们想基于 docker 镜像编译 kubernetes 的话,那么还需要安装 docker 环境。

3、安装依赖 golang、docker

3.1、安装 golang

注意:kubernetes 1.13 版本需要依赖的 go 版本 >= 1.11.1,所以安装时需选择该版本以上,否则下边编译时会报错终止,提示需要升级 go 版本,这里提供两种方式安装 golang 环境。

一、直接下载源码安装(注意此方式需要机器网络可以越过墙)

$ cd /opt && wget -c https://dl.google.com/go/go1.11.5.linux-amd64.tar.gz
$ tar -C /usr/local -xzf go1.11.4.linux-amd64.tar.gz 
$ echo "export PATH=$PATH:/usr/local/go/bin" >> /etc/profile
$ source /etc/profile

二、通过 rpm 包 yum 安装

$ cd /opt && wget http://download-ib01.fedoraproject.org/pub/epel/7/x86_64/Packages/g/golang-1.11.5-1.el7.x86_64.rpm
$ yum -y install golang-1.11.5-1.el7.x86_64.rpm

安装完毕后,执行 go version 能输出对应的版本号,说明安装没有问题。最后,为了方便编译,最好配置一下 GOPATH 作为 go 执行的工作路径。

$ echo "GOPATH=/root/go" >> /etc/profile
$ source /etc/profile

3.2、安装 docker

docker 安装非常方便,针对自己系统参照 Docker 官网文档 安装即可,这里简单操作一下吧!

一键式安装方式:

$ curl -fsSL https://get.docker.com -o get-docker.sh
$ sudo sh get-docker.sh

rpm 包 yum 安装方式:

$ wget https://download.docker.com/linux/centos/7/x86_64/stable/Packages/docker-ce-18.06.1.ce-3.el7.x86_64.rpm
$ yum -y install docker-ce-18.06.1.ce-3.el7.x86_64.rpm
$ systemctl enable docker
$ systemctl start docker

yum 源安装方式:

$ yum install -y yum-utils device-mapper-persistent-data lvm2
$ yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$ yum install docker-ce docker-ce-cli containerd.io
$ systemctl enable docker
$ systemctl start docker

安装完毕后,执行 docker -v 命令能输出对应版本号,说明安装没问题。

4、二进制可执行文件编译 kubernetes

开始执行编译前,我们需要将 kubernetes 源码 拉取到本地 GOPATH 工作路径,并指定好 release-1.13 稳定分支。

$ mkdir -p $GOPATH/src/k8s.io && cd $GOPATH/src/k8s.io
$ git clone  https://github.com/kubernetes/kubernetes -b release-1.13
$ cd kubernetes

我们从 kubernetes/hack/lib/golang.sh 代码中可以看到,该脚本会检测当前系统环境来安装对应的必要的服务,默认不指定 KUBE_BUILD_PLATFORMS(当前构建平台环境类型)的话,它会分别编译多种环境,编译时间很长,而且没有必要。这里我们可以直接修改文件中 KUBE_SERVER_PLATFORMS KUBE_NODE_PLATFORMS KUBE_CLIENT_PLATFORMS KUBE_TEST_PLATFORMS 配置,只保留当前系统对应环境,例如我们的系统环境为 linux/amd64。另一种方式就是在编译时,直接指定 KUBE_BUILD_PLATFORMS 参数即可。编译命令如下:

$ KUBE_BUILD_PLATFORMS=linux/amd64 make all GOFLAGS=-v GOGCFLAGS="-N -l"

对参数简单说明一下:

  • KUBE_BUILD_PLATFORMS=linux/amd64 指定当前编译平台环境类型为 linux/amd64
  • make all 表示在本地环境中编译所有组件。
  • GOFLAGS=-v 编译参数,开启 verbose 日志。
  • GOGCFLAGS="-N -l" 编译参数,禁止编译优化和内联,减小可执行程序大小。

注意:执行以上命令时,需要机器可用内存在 4G 左右,否则编译时会报内存不够错误。若我们只想编译某个组件,例如,只想编译 kube-apiserver ,那么可以执行 make WHAT=cmd/kube-apiserver 命令。这里可选组件有很多,详细可参考 kubernetes/cmd/ 目录下所有组件。

稍等片刻,全部组件编译耗时较长,执行完毕后,二进制可执行文件默认生成到 kubernetes/_output/bin 目录下。

$ ll _output/bin/
total 1372584
-rwxr-xr-x 1 root root  39777728 Feb 20 16:32 apiextensions-apiserver
-rwxr-xr-x 1 root root  89522240 Feb 20 16:32 cloud-controller-manager
-rwxr-xr-x 1 root root   5800256 Feb 20 16:09 conversion-gen
-rwxr-xr-x 1 root root   5791968 Feb 20 16:08 deepcopy-gen
-rwxr-xr-x 1 root root   5783808 Feb 20 16:09 defaulter-gen
-rwxr-xr-x 1 root root  38382720 Feb 20 16:32 gendocs
-rwxr-xr-x 1 root root 174569288 Feb 20 16:32 genkubedocs
-rwxr-xr-x 1 root root 181003752 Feb 20 16:32 genman
-rwxr-xr-x 1 root root   3901568 Feb 20 16:32 genswaggertypedocs
-rwxr-xr-x 1 root root  38382720 Feb 20 16:32 genyaml
-rwxr-xr-x 1 root root   8126240 Feb 20 16:32 ginkgo
-rwxr-xr-x 1 root root   4460824 Feb 20 16:08 go2make
-rwxr-xr-x 1 root root   2005984 Feb 20 16:09 go-bindata
-rwxr-xr-x 1 root root 177541000 Feb 20 16:32 hyperkube
-rwxr-xr-x 1 root root  36350048 Feb 20 16:32 kubeadm
-rwxr-xr-x 1 root root 138505440 Feb 20 16:32 kube-apiserver
-rwxr-xr-x 1 root root 103774080 Feb 20 16:32 kube-controller-manager
-rwxr-xr-x 1 root root  39189984 Feb 20 16:32 kubectl
-rwxr-xr-x 1 root root 112883720 Feb 20 16:32 kubelet
-rwxr-xr-x 1 root root 110770664 Feb 20 16:32 kubemark
-rwxr-xr-x 1 root root  34775392 Feb 20 16:32 kube-proxy
-rwxr-xr-x 1 root root  37230848 Feb 20 16:32 kube-scheduler
-rwxr-xr-x 1 root root   4975168 Feb 20 16:32 linkcheck
-rwxr-xr-x 1 root root   1599264 Feb 20 16:32 mounter
-rwxr-xr-x 1 root root  10367840 Feb 20 16:09 openapi-gen

上边讲到单独对某个组件执行编译,除了上述办法之外,还可以进入到 kubernetes/cmd/ 目录下对应组件下执行,例如我们编译 kube-apiserver 组件。

$ cd kubernetes/cmd/kube-apiserver
$ go build -v
$ ls 
apiserver.go  app  kube-apiserver  BUILD  OWNERS

5、docker 镜像编译 kubernetes

docker 镜像编译 kubernetes,可以编译出各核心组件二进制文件以及对应的镜像文件,这里得提一下,由于国内网络的问题,想顺利的安装 kubernetes,依赖镜像拉取问题比较麻烦,之前文章也提到过,可以通过 Github 配合 DockerHub 的 Auto build 功能,将镜像推送到 DockerHub,然后本地拉取后修改 tag 名称,操作有点麻烦,不过好歹解决了我们镜像拉取不到的问题。现在我们可以本地编译出 kubernetes 依赖的镜像了,那就很方便了,有木有。

具体涉及到的代码目录为 kubernetes/build,这里主要包含几个核心基础镜像的制作,包括 kube-crosspause-amd64debian-iptables-amd64debian-base-amd64debian-hyperkube-base-amd64。这里我偷个懒,先不挨个构建了,当然依旧可以通过上边提到的途径解决,直接拿别人构建好的镜像,拉取后修改 tag 即可。

$ docker pull xiaoxu780/pause-amd64:3.1
$ docker pull xiaoxu780/kube-cross:v1.11.2-1
$ docker pull xiaoxu780/debian-base-amd64:0.4.0
$ docker pull xiaoxu780/debian-iptables-amd64:v11.0
$ docker pull xiaoxu780/debian-hyperkube-base-amd64:0.12.0

$ docker tag xiaoxu780/pause-amd64:3.1 k8s.gcr.io/pause-amd64:3.1
$ docker tag xiaoxu780/kube-cross:v1.11.2-1 k8s.gcr.io/kube-cross:v1.11.5-1
$ docker tag xiaoxu780/debian-base-amd64:0.4.0 k8s.gcr.io/debian-base-amd64:0.4.0
$ docker tag xiaoxu780/debian-iptables-amd64:v11.0 k8s.gcr.io/debian-iptables-amd64:v11.0
$ docker tag xiaoxu780/debian-hyperkube-base-amd64:0.12.0 k8s.gcr.io/debian-hyperkube-base-amd64:0.12.0

注意:这里通过 kube-cross 组件有指定的版本,可以从 kubernetes/build/build-image/cross/VERSION 文件得到,我这里显示是 v1.11.5-1,跟上边提供的版本不一致,不过没关系,直接修改为该版本 tag 亲测没有问题的。

依赖的基础镜像本地已经有了,接下来需要修改构建策略,忽略 --pull 参数,不然每次构建还是会去外网拉取基础镜像,要让它直接读取本地镜像。修改 kubernetes/build/lib/release.sh 文件如下:

"${DOCKER[@]}" build --pull -q -t "${docker_image_tag}" "${docker_build_path}" >/dev/null
修改为
"${DOCKER[@]}" build -q -t "${docker_image_tag}" "${docker_build_path}" >/dev/null

其次修改 kubernetes/hack/lib/version.sh 文件,将变量 KUBE_GIT_TREE_STATE="dirty" 修改为 KUBE_GIT_TREE_STATE="clean"dirty 表示 Git 提交 ID 之后的源代码有更改,clean 表示 Git 提交 ID 之后没有更改,为了确保版本号干净,都修改为 clean

接下来直接执行如下编译命令:

$ KUBE_BUILD_PLATFORMS=linux/amd64 KUBE_BUILD_CONFORMANCE=n KUBE_BUILD_HYPERKUBE=n make release-images GOFLAGS=-v GOGCFLAGS="-N -l"
+++ [0221 10:48:26] Verifying Prerequisites....
+++ [0221 10:48:27] Building Docker image kube-build:build-d0824d4b8f-5-v1.11.5-1
+++ [0221 10:48:49] Creating data container kube-build-data-d0824d4b8f-5-v1.11.5-1
+++ [0221 10:48:53] Syncing sources to container
+++ [0221 10:49:11] Running build command...
......
+++ [0221 10:56:08] Syncing out of container
+++ [0221 10:56:13] Building images: linux-amd64
+++ [0221 10:56:14] Starting docker build for image: cloud-controller-manager-amd64
+++ [0221 10:56:14] Starting docker build for image: kube-apiserver-amd64
+++ [0221 10:56:14] Starting docker build for image: kube-controller-manager-amd64
+++ [0221 10:56:14] Starting docker build for image: kube-scheduler-amd64
+++ [0221 10:56:14] Starting docker build for image: kube-proxy-amd64
+++ [0221 10:56:24] Deleting docker image k8s.gcr.io/kube-scheduler:v1.13.4-beta.0.12_4ef32ffb4e7c35
+++ [0221 10:56:25] Deleting docker image k8s.gcr.io/kube-proxy:v1.13.4-beta.0.12_4ef32ffb4e7c35
+++ [0221 10:56:32] Deleting docker image k8s.gcr.io/cloud-controller-manager:v1.13.4-beta.0.12_4ef32ffb4e7c35
+++ [0221 10:56:33] Deleting docker image k8s.gcr.io/kube-controller-manager:v1.13.4-beta.0.12_4ef32ffb4e7c35
+++ [0221 10:56:33] Deleting docker image k8s.gcr.io/kube-apiserver:v1.13.4-beta.0.12_4ef32ffb4e7c35
+++ [0221 10:56:33] Docker builds done

说明一下:

  • UBE_BUILD_CONFORMANCE=nKUBE_BUILD_HYPERKUBE=n 参数配置是否构建 hyperkube-amd64conformance-amd64 镜像,默认是 y 构建,这里设置为 n 暂时不需要构建了。
  • make release-images 表示执行编译并生成镜像 tar 包。

稍等片刻,编译的 kubernetes 组件 docker 镜像以 tar 包的形式发布在 kubernetes/_output/release-tars/amd64 目录中。

$ ll _output/release-images/amd64/
total 611988
-rw-r--r-- 2 root root 133416960 Feb 21 10:56 cloud-controller-manager.tar
-rw-r--r-- 2 root root 182395904 Feb 21 10:56 kube-apiserver.tar
-rw-r--r-- 2 root root 147664384 Feb 21 10:56 kube-controller-manager.tar
-rw-r--r-- 2 root root  82071552 Feb 21 10:56 kube-proxy.tar
-rw-r--r-- 2 root root  81121280 Feb 21 10:56 kube-scheduler.tar

生成的核心组件二进制可执行文件以及镜像,在 kubernetes/_output/release-stage/server/linux-amd64/kubernetes/server/bin/ 目录可以找到。

$ ll _output/release-stage/server/linux-amd64/kubernetes/server/bin/
total 1006368
-rwxr-xr-x 1 root root  89526336 Feb 21 10:56 cloud-controller-manager
-rw-r--r-- 1 root root        33 Feb 21 10:56 cloud-controller-manager.docker_tag
-rw-r--r-- 2 root root 133416960 Feb 21 10:56 cloud-controller-manager.tar
-rwxr-xr-x 1 root root 138505472 Feb 21 10:56 kube-apiserver
-rw-r--r-- 1 root root        33 Feb 21 10:56 kube-apiserver.docker_tag
-rw-r--r-- 2 root root 182395904 Feb 21 10:56 kube-apiserver.tar
-rwxr-xr-x 1 root root 103774112 Feb 21 10:56 kube-controller-manager
-rw-r--r-- 1 root root        33 Feb 21 10:56 kube-controller-manager.docker_tag
-rw-r--r-- 2 root root 147664384 Feb 21 10:56 kube-controller-manager.tar
-rwxr-xr-x 1 root root  34775392 Feb 21 10:56 kube-proxy
-rw-r--r-- 1 root root        33 Feb 21 10:56 kube-proxy.docker_tag
-rw-r--r-- 2 root root  82071552 Feb 21 10:56 kube-proxy.tar
-rwxr-xr-x 1 root root  37230848 Feb 21 10:56 kube-scheduler
-rw-r--r-- 1 root root        33 Feb 21 10:56 kube-scheduler.docker_t

这些镜像 tar 包是可以直接用的,这下再也不用担心镜像拉不下来了。

6、如何使用编译产物

之前我们使用 minikube 或 kubeadm 方式安装 kubernetes,都是基于 docker 镜像方式运行的,现在本地已经有镜像 tar 包了,只需要导入即可。

$ docker load -i kube-apiserver.tar
8b4af753a2e6: Loading layer  138.5MB/138.5MB
Loaded image: k8s.gcr.io/kube-apiserver:v1.13.4-beta.0.12_4ef32ffb4e7c35
$ docker load -i kube-controller-manager.tar
b6bc9feeea3e: Loading layer  103.8MB/103.8MB
Loaded image: k8s.gcr.io/kube-controller-manager:v1.13.4-beta.0.12_4ef32ffb4e7c35
$ docker load -i kube-proxy.tar
f809931d55f8: Loading layer  34.78MB/34.78MB
Loaded image: k8s.gcr.io/kube-proxy:v1.13.4-beta.0.12_4ef32ffb4e7c35
$ docker load -i kube-scheduler.tar
08c5e224b023: Loading layer  37.23MB/37.23MB
Loaded image: k8s.gcr.io/kube-scheduler:v1.13.4-beta.0.12_4ef32ffb4e7c35

$ docker images | grep kube
REPOSITORY                               TAG                                IMAGE ID            CREATED             SIZE
k8s.gcr.io/kube-apiserver                v1.13.4-beta.0.12_4ef32ffb4e7c35   478c9f2cf9b0        7 hours ago         181MB
k8s.gcr.io/kube-controller-manager       v1.13.4-beta.0.12_4ef32ffb4e7c35   2095dd7895ac        7 hours ago         146MB
k8s.gcr.io/kube-proxy                    v1.13.4-beta.0.12_4ef32ffb4e7c35   b22db5302318        7 hours ago         80.2MB
k8s.gcr.io/kube-scheduler                v1.13.4-beta.0.12_4ef32ffb4e7c35   d17edffb4bca        7 hours ago         79.6MB
kube-build                               build-d0824d4b8f-5-v1.11.5-1       1b02b2eeeffd        7 hours ago         2.31GB

对于二进制可执行文件,亦可直接使用,具体可参考 kubeasz 项目,该项目致力于提供快速部署高可用 k8s 集群的工具,它基于二进制可执行程序方式部署和利用 ansible-playbook 实现自动化安装的。

参考资料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章