國內環境下 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 實現自動化安裝的。

參考資料

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