kubernetes源碼閱讀
工欲善其事,必先利其器。在閱讀kubernetes源碼時,我也先后使用過多個IDE,最終還是停留在IDEA上。
我慣用的是pycharm(IDEA的python IDE版本),配上go的插件,把源碼目錄進行合理組織后,加入到go的lib,即可實現跳轉。更多的方法可以參看這里。
kubernetes源碼編譯
kubernetes的源碼編譯可以分為兩種方式。一種是在宿主機/物理機上進行編譯,這就意味着你需要完整的搭建編譯環境,這個會依賴於各種問題,做法相當不fashion。另外一種則是使用docker進行編譯。這也是目前最為流行的編譯方式。
使用docker進行編譯
本文以kubernetes 1.2為例進行介紹。
kubernetes自身提供了基於docker的編譯方式,按照說明,只需要運行
run.sh hack/build-go.sh
即可從源碼編譯出對應的二進制文件。
流程詳解
可以看到run.sh中有如下幾個步驟:
kube::build::verify_prereqs
kube::build::build_image
kube::build::run_build_command "$@"
verify_prereqs
kube::build::verify_prereqs
是為編譯做一些檢查,包括檢查需要的鏡像是否存在等。
build_image
kube::build::build_image
這一步驟主要是根據Dockerfile,進行構建鏡像。這一步驟如下:
function kube::build::build_image() {
kube::build::ensure_tar
mkdir -p "${LOCAL_OUTPUT_BUILD_CONTEXT}"
//對於源碼進行打包,打成tar包
"${TAR}" czf "${LOCAL_OUTPUT_BUILD_CONTEXT}/kube-source.tar.gz" $(kube::build::source_targets)
kube::version::get_version_vars
kube::version::save_version_vars "${LOCAL_OUTPUT_BUILD_CONTEXT}/kube-version-defs"
//組織待構建鏡像的文件夾
cp build/build-image/Dockerfile "${LOCAL_OUTPUT_BUILD_CONTEXT}/Dockerfile"
kube::build::update_dockerfile
//構建鏡像
kube::build::docker_build "${KUBE_BUILD_IMAGE}" "${LOCAL_OUTPUT_BUILD_CONTEXT}" 'false'
}
待構建鏡像的文件夾位於_output
文件夾中。可以看到_output
的目錄結構如下:
[root@localhost kubernetes]# tree _output/
_output/
└── images
└── kube-build:build-cbc077d244
├── Dockerfile
├── kube-source.tar.gz
└── kube-version-defs
kube-source.tar.gz
即為kubernetes源碼打成的tar包。Dockerfile即為build-image/Dockerfile文件。
之后docker build
將在kube-build:build-cbc077d244
文件夾中進行,編譯成kube-build:build-cbc077d244
的鏡像。
cbc077d244為git提交時的id,根據源碼commit時情況不同該id不同。
[root@localhost kubernetes]# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
kube-build build-cbc077d244 46bca394905f 42 hours ago 1.628 GB
gcr.io/google_containers/kube-cross v1.4.2-1 eb4273dc5e30 5 months ago 1.551 GB
run_build_command
到現在為止,必要的工作已經基本做完,代碼也已經打包進入鏡像,此時只要使用docker從kube-build:build-cbc077d244
的鏡像run一個容器出來,進行編譯即可。
實際kube::build::run_build_command
也就是這樣工作的。不過這里面還做了一些額外的工作,比如把編譯輸出的文件夾通過-v
參數掛載到_output/dockerized/bin
下。這樣當編譯完成之后,生成的二進制文件就可以直接在_output/dockerized/bin
目錄下獲取了。
這一過程參見common.sh#L75
實際問題
一條命令進行編譯的願望很美好。但是理想很豐滿,現實很骨感,在實際中有一些問題,導致這一編譯不能正常進行。其中首要的問題就是鏡像無法拉取的問題。
鏡像無法拉取
Dockerfile中的第一行命令:
FROM gcr.io/google_containers/kube-cross:KUBE_BUILD_IMAGE_CROSS_TAG
。因此需要依賴於gcr.io/google_containers/kube-cross:KUBE_BUILD_IMAGE_CROSS_TAG
這個鏡像。但是由於網絡原因,往往無法正常拉取該鏡像。所以會導致鏡像構建失敗。
對於這一問題,有兩種方式可以解決:
- 自己進行構建kube-cross鏡像
- 通過代理或者其他方式,獲取
gcr.io/google_containers/kube-cross:KUBE_BUILD_IMAGE_CROSS_TAG
鏡像
本文主要介紹前一種方式。其實kube-cross鏡像的內容,可以在kube-cross文件夾中獲取。當然,要想在國內直接構建這個鏡像,仍然會存在無法下載部分包的問題。這里我使用了靈雀雲的系統來構建這個鏡像。這里是我的kubernetes鏡像。
所以你需要做的只是運行以下命令即可:
docker pull index.alauda.cn/xuxinkun/kubernetes
docker tag index.alauda.cn/xuxinkun/kubernetes gcr.io/google_containers/kube-cross:v1.4.2-1
編譯極為耗時
當使用run.sh hack/build-go.sh
會編譯項目中linux下的所有二進制文件。這一過程極為耗時,大概要十幾分鍾的樣子。根據配置不同時間或有增減。
其實在實際過程中,並不需要每次編譯所有的文件。比如本次只需要kubelet,那么可以直接運行run.sh hack/build-go.sh cmd/kubelet
,即可只編譯kubelet文件,縮短編譯時間。